diff --git a/CHANGELOG.md b/CHANGELOG.md index df9b4348..3a57b70f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +* **role:trend_micro**: Add a role to install and activate the Trend Vision One Endpoint Security agent (Endpoint Sensor and Server & Workload Protection) on RHEL 9 and RHEL 10. * **role:matomo_import_logs**: New role that imports Apache access logs into Matomo on a schedule, one systemd timer per site, and ships the Matomo log-analytics import script (`import_logs.py`). The `token_auth` is provided via a per-site auth file instead of the command line (passing `--token-auth`, `--login` or `--password` is deprecated, since they are visible in the process list and now log a deprecation warning). The script also supports the Traefik access-log format and fixes a possible endless loop when reading a config file. * **role:glances**: Add RHEL 10 / Rocky 10 / Alma 10 support by installing glances into a Python venv via the `python_venv` role, since the package is not available in EPEL 10. RHEL 10 is now marked proven (`x`) in COMPATIBILITY. * **role:graylog_datanode**: Add `graylog_datanode__http_publish_uri` to set the REST API URI the DataNode advertises, needed when the bind address is not directly reachable (multiple interfaces, a NAT gateway, or a `0.0.0.0` bind address). diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index 6de4f3b6..c9283ef2 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -162,6 +162,7 @@ Which Ansible role is proven to run on which OS? | timezone | (x) | (x) | x | x | x | (x) | (x) | (x) | Fedora 35 | | tmux | (x) | (x) | (x) | x | (x) | (x) | (x) | (x) | | | tools | | | x | x | x | | | | Fedora | +| trend_micro | | | x | x | x | | | | | | unattended_upgrades | (x) | (x) | | | | (x) | (x) | (x) | | | uptimerobot | | | | | | | | | controller-side, talks to UptimeRobot API | | vsftpd | | | x | (x) | (x) | | | | | diff --git a/playbooks/README.md b/playbooks/README.md index 3d435fdd..17a0c904 100644 --- a/playbooks/README.md +++ b/playbooks/README.md @@ -1381,6 +1381,13 @@ Calls the following roles (in order): * [tools](https://github.com/Linuxfabrik/lfops/tree/main/roles/tools) +## trend_micro.yml + +Calls the following roles (in order): + +* [trend_micro](https://github.com/Linuxfabrik/lfops/tree/main/roles/trend_micro) + + ## unattended_upgrades.yml Calls the following roles (in order): diff --git a/playbooks/all.yml b/playbooks/all.yml index c22201a4..82b509c4 100644 --- a/playbooks/all.yml +++ b/playbooks/all.yml @@ -145,6 +145,7 @@ - import_playbook: 'timezone.yml' - import_playbook: 'tmux.yml' - import_playbook: 'tools.yml' +- import_playbook: 'trend_micro.yml' - import_playbook: 'unattended_upgrades.yml' - import_playbook: 'vsftpd.yml' - import_playbook: 'yum_utils.yml' diff --git a/playbooks/trend_micro.yml b/playbooks/trend_micro.yml new file mode 100644 index 00000000..12e2177e --- /dev/null +++ b/playbooks/trend_micro.yml @@ -0,0 +1,23 @@ +- name: 'Playbook linuxfabrik.lfops.trend_micro' + hosts: + - 'lfops_trend_micro' + + pre_tasks: + - ansible.builtin.import_role: + name: 'shared' + tasks_from: 'log-start.yml' + tags: + - 'always' + + + roles: + + - role: 'linuxfabrik.lfops.trend_micro' + + + post_tasks: + - ansible.builtin.import_role: + name: 'shared' + tasks_from: 'log-end.yml' + tags: + - 'always' diff --git a/roles/trend_micro/README.md b/roles/trend_micro/README.md new file mode 100644 index 00000000..560b02aa --- /dev/null +++ b/roles/trend_micro/README.md @@ -0,0 +1,138 @@ +# Ansible Role linuxfabrik.lfops.trend_micro + +This role installs and activates the [Trend Vision One Endpoint Security](https://www.trendmicro.com/en_us/business/products/hybrid-cloud/vision-one-endpoint-security.html) agent (`v1es`) on Linux servers. It covers pre-flight checks, agent download and installation via the XBC API, agent registration, and Server & Workload Protection (SWP) activation. + + +*Available in the next LFOps release.* + + +## Background: Two Products, One Host + +Trend Vision One Endpoint Security combines two products on the same host, and this role configures both: + +* **Endpoint Sensor** (XDR/EDR) is the `tmxbc` / Endpoint Basecamp agent. It is downloaded and installed through the XBC API. It is configured via `customer_id`, the per-architecture `company_id` and `scenario_ids`, `xbc_fqdn`, and `xbc_env`. +* **Server & Workload Protection (SWP)** is the Deep Security agent (`ds_agent`). It ships inside the same full package and is activated against a Deep Security Manager (DSM). It is configured via `tenant_id`, `token`, `swp_dsm_fqdn`, and the optional `policy_id`, `group_id`, and `relay_group_id`. + +The **Server & Workload Protection (SWP) deployment script** generated in the Vision One console contains every value the role needs. It bundles both products in one full package: it lists two scenario IDs (one for the Endpoint Sensor, one for SWP) and carries the SWP activation values. The role installs that package, waits for the SWP agent to come up, and then activates it against the DSM. + +> **Use the SWP deployment script, not the Endpoint-Sensor-only one.** The Endpoint-Sensor-only script lists a single scenario ID and none of the SWP activation values (tenant ID, token, DSM FQDN), so the SWP agent (`ds_agent`) cannot be installed. + + +## Generating the Deployment Script + +1. In the Vision One console, make sure a **Server & Workload Protection** product instance exists. If not, create it under **Service Management → Create product instance → Server & Workload Protection**. +2. Navigate to **Endpoint Security → Endpoint Inventory → Agent Installer → Deployment Script**. +3. Select **Server & Workload Protection** as the endpoint group and **Linux** as the operating system. +4. The previewed script contains every value the role needs. + +The script is a `bash` installer. Map its values to the role variables as follows (the script has separate `x86_64` and `aarch64` blocks, so `company_id` and `scenario_ids` differ per architecture): + +| Role variable | Where it appears in the deployment script | +| ------------- | ----------------------------------------- | +| `trend_micro__customer_id` | `CUSTOMER_ID="..."` | +| `trend_micro__group_id` | `GROUP_ID=...` (optional, defaults to `0`) | +| `trend_micro__policy_id` | `POLICY_ID=...` (optional, defaults to `0`) | +| `trend_micro__relay_group_id` | `RELAY_GROUP_ID=...` (optional, defaults to `0`) | +| `trend_micro__swp_dsm_fqdn` | the host in `dsa_control -a dsm://:443/` | +| `trend_micro__swp_login.tenant_id` | `tenantID:...` in the `dsa_control` activation line | +| `trend_micro__swp_login.token` | `token:...` in the `dsa_control` activation line | +| `trend_micro__xbc_env` | `XBC_ENV="..."` (optional, defaults to `prod-eu1`) | +| `trend_micro__xbc_fqdn` | `XBC_FQDN="..."` | +| `trend_micro__xbc_installer__company_id` | `company_id` in the `HTTP_BODY` of the matching `archType` block | +| `trend_micro__xbc_installer__scenario_ids` | `scenario_ids` in the `HTTP_BODY` of the matching `archType` block (both IDs) | + + +## Relevant Information + +Learn about Trend Micro Concepts and Products: https://docs.linuxfabrik.ch/software/trend-micro.html +Agent Platform Compability: https://help.deepsecurity.trendmicro.com/20_0/on-premise/agent-compatibility.html + +## Mandatory Requirements + +* At least 2 GB of RAM. The Server & Workload Protection agent (`ds_agent`) enforces this minimum during its pre-check; on a host with less memory the pre-check fails and `ds_agent` is never installed. +* Running as `root` (use `become: true`). +* `/tmp` must be writable on the target host. + +Supported architectures: `x86_64`, `aarch64`. + + +## Tags + +| Tag | What it does | Reload / Restart | +| --- | ------------ | ---------------- | +| `trend_micro` | Runs all tasks | - | +| `trend_micro:install` | Installs `curl` and `tar` only | - | + + +## Mandatory Role Variables + +| Variable | Description | +| -------- | ----------- | +| `trend_micro__customer_id` | Customer ID used in the installer API request. Found in the Vision One deployment script preview. | +| `trend_micro__xbc_installer_x86_64_company_id` | Company ID for the x86\_64 installer API request. | +| `trend_micro__xbc_installer_x86_64_scenario_ids` | List of scenario IDs for the x86\_64 installer API request. Include all IDs from the deployment script (endpoint sensor and SWP).| +| `trend_micro__xbc_installer_aarch64_company_id` | Company ID for the aarch64 installer API request. | +| `trend_micro__xbc_installer_aarch64_scenario_ids` | List of scenario IDs for the aarch64 installer API request. Include all IDs from the deployment script (endpoint sensor and SWP).| +| `trend_micro__swp_dsm_fqdn` | Deep Security Manager FQDN used to activate Server & Workload Protection. | +| `trend_micro__swp_login` | Server & Workload Protection activation credentials. Dictionary with the keys `tenant_id` and `token`. Typically fed by `linuxfabrik.lfops.bitwarden_item`. | + +Example: +```yaml +# mandatory +trend_micro__customer_id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + +trend_micro__xbc_installer_x86_64_company_id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' +trend_micro__xbc_installer_x86_64_scenario_ids: + - '' + - '' + +trend_micro__xbc_installer_aarch64_company_id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' +trend_micro__xbc_installer_aarch64_scenario_ids: + - '' + - '' + +trend_micro__swp_dsm_fqdn: 'agents.workload.de-1.cloudone.trendmicro.com' +trend_micro__swp_login: + tenant_id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + token: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' +``` + + +## Optional Role Variables + +| Variable | Description | Default Value | +| -------- | ----------- | ------------- | +| `trend_micro__xbc_fqdn` | XBC backend FQDN. Use the FQDN matching your region. | `'api-eu1.xbc.trendmicro.com'` | +| `trend_micro__xbc_env` | XBC environment identifier. | `'prod-eu1'` | +| `trend_micro__policy_id` | Security policy to apply. `0` means no specific policy. | `0` | +| `trend_micro__group_id` | Agent group for organisation. | `0` | +| `trend_micro__relay_group_id` | Relay group for agent communication. | `0` | +| `trend_micro__proxy_addr` | Proxy hostname or IP. Leave empty for a direct connection. | `''` | +| `trend_micro__proxy_port` | Proxy port. | `''` | +| `trend_micro__proxy_login` | Proxy credentials. Dictionary with the keys `username` and `password`. Omit for a proxy that needs no authentication. | `{}` | +| `trend_micro__path_dsa` | Path to the `dsa_control` binary. | `'/opt/ds_agent/dsa_control'` | +| `trend_micro__path_identity_file` | Path polled to confirm agent registration. | `'/opt/TrendMicro/EndpointBasecamp/etc/.identity'` | + +Example: +```yaml +# optional +trend_micro__xbc_fqdn: 'api-us1.xbc.trendmicro.com' +trend_micro__policy_id: 42 +trend_micro__group_id: 10 +trend_micro__relay_group_id: 5 +trend_micro__proxy_addr: '192.0.2.30' +trend_micro__proxy_port: '8080' +trend_micro__proxy_login: + username: 'proxyuser' + password: 'linuxfabrik' +``` + + +## License + +[The Unlicense](https://unlicense.org/) + + +## Author Information + +[Linuxfabrik GmbH, Zurich](https://www.linuxfabrik.ch) diff --git a/roles/trend_micro/defaults/main.yml b/roles/trend_micro/defaults/main.yml new file mode 100644 index 00000000..01ec8398 --- /dev/null +++ b/roles/trend_micro/defaults/main.yml @@ -0,0 +1,10 @@ +trend_micro__group_id: 0 +trend_micro__path_dsa: '/opt/ds_agent/dsa_control' +trend_micro__path_identity_file: '/opt/TrendMicro/EndpointBasecamp/etc/.identity' +trend_micro__policy_id: 0 +trend_micro__proxy_addr: '' +trend_micro__proxy_login: {} +trend_micro__proxy_port: '' +trend_micro__relay_group_id: 0 +trend_micro__xbc_env: 'prod-eu1' +trend_micro__xbc_fqdn: 'api-eu1.xbc.trendmicro.com' diff --git a/roles/trend_micro/meta/argument_specs.yml b/roles/trend_micro/meta/argument_specs.yml new file mode 100644 index 00000000..a175d772 --- /dev/null +++ b/roles/trend_micro/meta/argument_specs.yml @@ -0,0 +1,108 @@ +argument_specs: + main: + options: + + trend_micro__customer_id: + type: 'str' + required: true + description: 'Customer ID used in the installer API request.' + + trend_micro__group_id: + type: 'int' + required: false + default: 0 + description: 'Agent group for organisation. 0 means no specific choice.' + + trend_micro__path_dsa: + type: 'str' + required: false + default: '/opt/ds_agent/dsa_control' + description: 'Path to the dsa_control binary.' + + trend_micro__path_identity_file: + type: 'str' + required: false + default: '/opt/TrendMicro/EndpointBasecamp/etc/.identity' + description: 'Path polled to confirm agent registration.' + + trend_micro__policy_id: + type: 'int' + required: false + default: 0 + description: 'Security policy to apply. 0 means no specific choice.' + + trend_micro__proxy_addr: + type: 'str' + required: false + default: '' + description: 'Proxy hostname or IP. Leave empty for a direct connection.' + + trend_micro__proxy_login: + type: 'dict' + required: false + default: {} + description: >- + Proxy credentials. May contain the keys `username` and `password`. + Typically fed by `linuxfabrik.lfops.bitwarden_item`, which returns the + full Bitwarden item; extra keys are ignored. Omit for a proxy that + needs no authentication. + + trend_micro__proxy_port: + type: 'str' + required: false + default: '' + description: 'Proxy port.' + + trend_micro__relay_group_id: + type: 'int' + required: false + default: 0 + description: 'Relay group for agent communication. 0 means no specific choice.' + + trend_micro__swp_dsm_fqdn: + type: 'str' + required: true + description: 'Deep Security Manager FQDN used to activate Server & Workload Protection.' + + trend_micro__swp_login: + type: 'dict' + required: true + description: >- + Server & Workload Protection activation credentials. Must contain the + keys `tenant_id` and `token`. Typically fed by + `linuxfabrik.lfops.bitwarden_item`, which returns the full Bitwarden + item; extra keys are ignored. + + trend_micro__xbc_env: + type: 'str' + required: false + default: 'prod-eu1' + description: 'XBC environment identifier.' + + trend_micro__xbc_fqdn: + type: 'str' + required: false + default: 'api-eu1.xbc.trendmicro.com' + description: 'XBC backend FQDN. Use the FQDN matching your region.' + + trend_micro__xbc_installer_aarch64_company_id: + type: 'str' + required: true + description: 'Company ID for the aarch64 installer API request.' + + trend_micro__xbc_installer_aarch64_scenario_ids: + type: 'list' + elements: 'str' + required: true + description: 'List of scenario IDs for the aarch64 installer API request.' + + trend_micro__xbc_installer_x86_64_company_id: + type: 'str' + required: true + description: 'Company ID for the x86_64 installer API request.' + + trend_micro__xbc_installer_x86_64_scenario_ids: + type: 'list' + elements: 'str' + required: true + description: 'List of scenario IDs for the x86_64 installer API request.' diff --git a/roles/trend_micro/tasks/main.yml b/roles/trend_micro/tasks/main.yml new file mode 100644 index 00000000..4f0e4ab4 --- /dev/null +++ b/roles/trend_micro/tasks/main.yml @@ -0,0 +1,281 @@ +- block: + + - name: 'stat /tmp' + ansible.builtin.stat: + path: '/tmp' + register: 'trend_micro__tmp_stat' + + - name: 'assert /tmp is writable' + ansible.builtin.assert: + that: + - 'trend_micro__tmp_stat.stat.writeable' + fail_msg: '/tmp is not writable. Please check the permissions of /tmp.' + + # ds_agent enforces this minimum during its own pre-check + - name: 'assert at least 2 GB of RAM (Server & Workload Protection requirement)' + ansible.builtin.assert: + that: + - 'ansible_facts.memtotal_mb | int >= 2048' + fail_msg: >- + Server & Workload Protection requires at least 2 GB of RAM; + this host has {{ ansible_facts.memtotal_mb }} MB. ds_agent will not install. + + tags: + - 'trend_micro' + + +- block: + + - name: 'package_facts' + ansible.builtin.package_facts: + check_mode: false + + - name: 'install curl' + ansible.builtin.package: + name: 'curl' + state: 'present' + + - name: 'install tar' + ansible.builtin.package: + name: 'tar' + state: 'present' + + tags: + - 'trend_micro:install' + + +- block: + + - name: 'Set proxy and connection config facts (proxy with username and password)' + ansible.builtin.set_fact: + trend_micro__proxy_env: + HTTP_PROXY: 'http://{{ trend_micro__proxy_login["username"] }}:{{ trend_micro__proxy_login["password"] }}@{{ trend_micro__proxy_addr }}:{{ trend_micro__proxy_port }}/' + HTTPS_PROXY: 'http://{{ trend_micro__proxy_login["username"] }}:{{ trend_micro__proxy_login["password"] }}@{{ trend_micro__proxy_addr }}:{{ trend_micro__proxy_port }}/' + trend_micro__proxy_config: '{{ (trend_micro__proxy_login["username"] + ":" + trend_micro__proxy_login["password"]) | b64encode }}@{{ trend_micro__proxy_addr }}:{{ trend_micro__proxy_port }}' + trend_micro__connect_config: '{{ {"fps": [{"connections": [{"type": "USER_INPUT"}]}]} | to_json | b64encode }}' + when: + - 'trend_micro__proxy_addr | length > 0' + - 'trend_micro__proxy_login["username"] | d("") | length > 0' + - 'trend_micro__proxy_login["password"] | d("") | length > 0' + + - name: 'Set proxy and connection config facts (proxy with username only)' + ansible.builtin.set_fact: + trend_micro__proxy_env: + HTTP_PROXY: 'http://{{ trend_micro__proxy_login["username"] }}@{{ trend_micro__proxy_addr }}:{{ trend_micro__proxy_port }}/' + HTTPS_PROXY: 'http://{{ trend_micro__proxy_login["username"] }}@{{ trend_micro__proxy_addr }}:{{ trend_micro__proxy_port }}/' + trend_micro__proxy_config: '{{ (trend_micro__proxy_login["username"] + ":") | b64encode }}@{{ trend_micro__proxy_addr }}:{{ trend_micro__proxy_port }}' + trend_micro__connect_config: '{{ {"fps": [{"connections": [{"type": "USER_INPUT"}]}]} | to_json | b64encode }}' + when: + - 'trend_micro__proxy_addr | length > 0' + - 'trend_micro__proxy_login["username"] | d("") | length > 0' + - 'trend_micro__proxy_login["password"] | d("") | length == 0' + + - name: 'Set proxy and connection config facts (proxy without credentials)' + ansible.builtin.set_fact: + trend_micro__proxy_env: + HTTP_PROXY: 'http://{{ trend_micro__proxy_addr }}:{{ trend_micro__proxy_port }}/' + HTTPS_PROXY: 'http://{{ trend_micro__proxy_addr }}:{{ trend_micro__proxy_port }}/' + trend_micro__proxy_config: '{{ trend_micro__proxy_addr }}:{{ trend_micro__proxy_port }}' + trend_micro__connect_config: '{{ {"fps": [{"connections": [{"type": "USER_INPUT"}]}]} | to_json | b64encode }}' + when: + - 'trend_micro__proxy_addr | length > 0' + - 'trend_micro__proxy_login["username"] | d("") | length == 0' + + - name: 'Set connection config facts (direct connection)' + ansible.builtin.set_fact: + trend_micro__proxy_env: {} + trend_micro__proxy_config: '' + trend_micro__connect_config: '{{ {"fps": [{"connections": [{"type": "DIRECT_CONNECT"}]}]} | to_json | b64encode }}' + when: 'trend_micro__proxy_addr | length == 0' + + tags: + - 'trend_micro' + +# in original script, this part below is being done by a platform detection script https://api-eu1.xbc.trendmicro.com/apk/platform-detection-script +- block: + + - name: 'Set x86_64 installer facts' + ansible.builtin.set_fact: + trend_micro__installer_body: + company_id: '{{ trend_micro__xbc_installer_x86_64_company_id }}' + platform: 'linux64' + scenario_ids: '{{ trend_micro__xbc_installer_x86_64_scenario_ids }}' + trend_micro__xbc_agent_token: "{{ trend_micro__xbc_installer_x86_64_scenario_ids | join('|') }}" + when: "ansible_architecture == 'x86_64'" + + - name: 'Set aarch64 installer facts' + ansible.builtin.set_fact: + trend_micro__installer_body: + company_id: '{{ trend_micro__xbc_installer_aarch64_company_id }}' + platform: 'linuxaarch64' + scenario_ids: '{{ trend_micro__xbc_installer_aarch64_scenario_ids }}' + trend_micro__xbc_agent_token: "{{ trend_micro__xbc_installer_aarch64_scenario_ids | join('|') }}" + when: "ansible_architecture == 'aarch64'" + + - name: 'assert supported architecture' + ansible.builtin.assert: + that: "ansible_architecture in ['x86_64', 'aarch64']" + fail_msg: 'Architecture {{ ansible_architecture }} is not supported.' + + tags: + - 'trend_micro' + + +- block: + + - name: 'file state=absent /tmp/v1es_installer.tgz # force a fresh download' + ansible.builtin.file: + path: '/tmp/v1es_installer.tgz' + state: 'absent' + + - name: 'download installer to /tmp/v1es_installer.tgz' + ansible.builtin.uri: + url: 'https://{{ trend_micro__xbc_fqdn }}/apk/installer' + method: 'POST' + headers: + X-Customer-Id: '{{ trend_micro__customer_id }}' + body: '{{ trend_micro__installer_body }}' + body_format: 'json' + dest: '/tmp/v1es_installer.tgz' + follow_redirects: 'all' # the API answers with 303, then 200 + status_code: + - 200 + environment: '{{ trend_micro__proxy_env }}' + + tags: + - 'trend_micro' + + +- block: + + - name: 'file state=directory /tmp/v1es' + ansible.builtin.file: + path: '/tmp/v1es' + state: 'directory' + mode: 0o755 + + - name: 'unarchive /tmp/v1es_installer.tgz to /tmp/v1es' + ansible.builtin.unarchive: + src: '/tmp/v1es_installer.tgz' + dest: '/tmp/v1es' + remote_src: true + + - name: 'copy /tmp/v1es/.property' + ansible.builtin.copy: + content: '{{ {"xbc_env": trend_micro__xbc_env, "xbc_agent_token": trend_micro__xbc_agent_token, "full_package": true} | to_json }}' + dest: '/tmp/v1es/.property' + mode: 0o644 + + tags: + - 'trend_micro' + + +- block: + + # tmxbc installs the Endpoint Basecamp agent on a fresh install that Basecamp socket may not exist yet, so the command exits non-zero + - name: '/tmp/v1es/tmxbc install --proxiesWithCred ... --connection ... (proxy)' + ansible.builtin.command: + argv: + - '/tmp/v1es/tmxbc' + - 'install' + - '--proxiesWithCred' + - '{{ trend_micro__proxy_config }}' + - '--connection' + - '{{ trend_micro__connect_config }}' + environment: '{{ trend_micro__proxy_env }}' + register: 'trend_micro__install_result' + until: 'trend_micro__install_result.rc == 0' + retries: 6 + delay: 10 + when: "trend_micro__proxy_config | length > 0" + + - name: '/tmp/v1es/tmxbc install --connection ... (direct)' + ansible.builtin.command: + argv: + - '/tmp/v1es/tmxbc' + - 'install' + - '--connection' + - '{{ trend_micro__connect_config }}' + register: 'trend_micro__install_result' + until: 'trend_micro__install_result.rc == 0' + retries: 6 + delay: 10 + when: "trend_micro__proxy_config | length == 0" + + tags: + - 'trend_micro' + + +- block: + + - name: 'wait_for path={{ trend_micro__path_identity_file }} # agent registration' + ansible.builtin.wait_for: + path: '{{ trend_micro__path_identity_file }}' + timeout: 300 + + tags: + - 'trend_micro' + + +# the SWP agent (ds_agent) ships inside the XBC full package, so it is deployed by tmxbc; wait for its service to come up and initialize, then activate it +- block: + + - name: 'systemctl is-active ds_agent # wait for SWP to install and start' + ansible.builtin.command: + cmd: 'systemctl is-active ds_agent' + register: 'trend_micro__ds_agent_status' + until: 'trend_micro__ds_agent_status.rc == 0' + retries: 60 + delay: 10 + changed_when: false + check_mode: false + + - name: 'wait_for path=/var/opt/ds_agent/dsa_core/ds_agent.crt # SWP initialization' + ansible.builtin.wait_for: + path: '/var/opt/ds_agent/dsa_core/ds_agent.crt' + timeout: 300 + + tags: + - 'trend_micro' + + +# the full package installs ds_agent but does not self-activate it against the SWP DSM; activation must be done explicitly with the tenant credentials, mirroring the vendor deployment script which always runs `dsa_control -a` +- block: + + - name: 'pause seconds=15 # let ds_agent finish initializing before activation' + ansible.builtin.pause: + seconds: 15 + + - name: '{{ trend_micro__path_dsa }} -a dsm://{{ trend_micro__swp_dsm_fqdn }}:443/ ... # activate SWP' + ansible.builtin.command: + argv: + - '{{ trend_micro__path_dsa }}' + - '-a' + - 'dsm://{{ trend_micro__swp_dsm_fqdn }}:443/' + - 'tenantID:{{ trend_micro__swp_login["tenant_id"] }}' + - 'token:{{ trend_micro__swp_login["token"] }}' + - 'policyid:{{ trend_micro__policy_id }}' + - 'relaygroupid:{{ trend_micro__relay_group_id }}' + - 'groupid:{{ trend_micro__group_id }}' + register: 'trend_micro__activation_result' + # ds_agent needs a moment after install before it can talk to the DSM + until: >- + '200' in trend_micro__activation_result.stdout or + 'reset agent first' in trend_micro__activation_result.stdout + retries: 12 + delay: 10 + changed_when: "'200' in trend_micro__activation_result.stdout" + failed_when: false + + - name: 'assert SWP is activated' + ansible.builtin.assert: + that: + - >- + '200' in trend_micro__activation_result.stdout or + 'reset agent first' in trend_micro__activation_result.stdout + fail_msg: >- + Server & Workload Protection activation failed. Output: + {{ trend_micro__activation_result.stdout | default('n/a') }}. + + tags: + - 'trend_micro'