Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
236 changes: 192 additions & 44 deletions .github/actions/cdr/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@ inputs:
default: "default"
required: false
type: string
okta-logs-url:
description: "Okta System Log API URL (e.g. https://dev-xxx.okta.com/api/v1/logs); empty skips Okta"
default: "default"
required: false
type: string
okta-api-key:
description: "Okta API token for System Log"
default: "default"
required: false
type: string
okta-entity-analytics-domain:
description: "Okta org hostname for Entity Analytics (e.g. dev-123456.okta.com); empty skips that integration"
default: "default"
required: false
type: string
es-user:
description: "Elasticsearch user"
default: "elastic"
Expand Down Expand Up @@ -100,6 +115,11 @@ inputs:
default: "cloudbeat"
required: false
type: string
enable-entity-store-v2:
description: "When true, run Entity Store v2 installer; when false, run Entity Store v1 only"
default: true
required: false
type: boolean

runs:
using: composite
Expand All @@ -113,9 +133,21 @@ runs:
TF_VAR_gcp_service_account_json: ${{ inputs.gcp-service-account-json }}
TF_VAR_project: ${{ inputs.tag-project }}
TF_VAR_owner: ${{ inputs.tag-owner }}
# This workflow always provisions both Elastic Defend VMs; use Terraform variables for selective applies outside CI.
TF_VAR_deploy_aws_elastic_defend_linux: true
TF_VAR_deploy_aws_elastic_defend_windows: true
shell: bash
working-directory: "deploy/test-environments/cdr"
run: |
# Restrict WinRM (5985) ingress to the runner egress IP.
# The ec2-windows module rejects empty / 0.0.0.0/0 to avoid exposing WinRM to the internet by default.
RUNNER_EGRESS_IP="$(curl -fsS https://checkip.amazonaws.com | tr -d '\n')"
if [[ -z "$RUNNER_EGRESS_IP" ]]; then
echo "Failed to determine runner egress IP for WinRM allowlist"
exit 1
fi
export TF_VAR_windows_elastic_defend_winrm_ingress_cidr="${RUNNER_EGRESS_IP}/32"

terraform init
terraform validate
terraform apply -auto-approve
Expand All @@ -125,46 +157,7 @@ runs:
if: success()
shell: bash
working-directory: "deploy/test-environments/cdr"
run: |
aws_ec2_cloudtrail_public_ip=$(terraform output -raw ec2_cloudtrail_public_ip)
echo "::add-mask::$aws_ec2_cloudtrail_public_ip"
echo "aws-ec2-cloudtrail-public-ip=$aws_ec2_cloudtrail_public_ip" >> "$GITHUB_OUTPUT"

aws_ec2_cloudtrail_key=$(terraform output -raw ec2_cloudtrail_key)
echo "::add-mask::$aws_ec2_cloudtrail_key"
echo "aws-ec2-cloudtrail-key=$aws_ec2_cloudtrail_key" >>"$GITHUB_OUTPUT"

az_vm_activity_logs_public_ip=$(terraform output -raw az_vm_activity_logs_public_ip)
echo "::add-mask::$az_vm_activity_logs_public_ip"
echo "az-vm-activity-logs-public-ip=$az_vm_activity_logs_public_ip" >> "$GITHUB_OUTPUT"

az_vm_activity_logs_key=$(terraform output -raw az_vm_activity_logs_key)
echo "::add-mask::$az_vm_activity_logs_key"
echo "az-vm-activity-logs-key=$az_vm_activity_logs_key" >> "$GITHUB_OUTPUT"

gcp_audit_logs_public_ip=$(terraform output -raw gcp_audit_logs_public_ip)
echo "::add-mask::$gcp_audit_logs_public_ip"
echo "gcp-audit-logs-public-ip=$gcp_audit_logs_public_ip" >> "$GITHUB_OUTPUT"

gcp_audit_logs_key=$(terraform output -raw gcp_audit_logs_key)
echo "::add-mask::$gcp_audit_logs_key"
echo "gcp-audit-logs-key=$gcp_audit_logs_key" >> "$GITHUB_OUTPUT"

ec2_asset_inv_key=$(terraform output -raw ec2_asset_inventory_key)
echo "::add-mask::$ec2_asset_inv_key"
echo "ec2-asset-inv-key=$ec2_asset_inv_key" >> "$GITHUB_OUTPUT"

asset_inv_public_ip=$(terraform output -raw ec2_asset_inventory_public_ip)
echo "::add-mask::$asset_inv_public_ip"
echo "asset-inv-public-ip=$asset_inv_public_ip" >> "$GITHUB_OUTPUT"

ec2_wiz_key=$(terraform output -raw ec2_wiz_key)
echo "::add-mask::$ec2_wiz_key"
echo "ec2-wiz-key=$ec2_wiz_key" >> "$GITHUB_OUTPUT"

ec2_wiz_public_ip=$(terraform output -raw ec2_wiz_public_ip)
echo "::add-mask::$ec2_wiz_public_ip"
echo "ec2-wiz-public-ip=$ec2_wiz_public_ip" >> "$GITHUB_OUTPUT"
run: ./export_terraform_outputs.sh

- name: Install AWS Cloudtrail integration
id: cloudtrail-integration
Expand Down Expand Up @@ -250,7 +243,7 @@ runs:

- name: Install WIZ integration
id: wiz-integration
if: ${{ !cancelled() && steps.deploy-cdr-infra.outcome == 'success' }}
if: ${{ !cancelled() && steps.deploy-cdr-infra.outcome == 'success' }}
working-directory: tests/integrations_setup
shell: bash
env:
Expand All @@ -264,8 +257,40 @@ runs:
run: |
poetry run python ./install_wiz_integration.py

- name: Install Okta integration (Fleet, Wiz agent policy)
id: okta-integration
if: ${{ !cancelled() && steps.deploy-cdr-infra.outcome == 'success' && steps.wiz-integration.outcome == 'success' }}
working-directory: tests/integrations_setup
shell: bash
env:
OKTA_LOGS_URL: ${{ inputs.okta-logs-url }}
OKTA_API_KEY: ${{ inputs.okta-api-key }}
ES_USER: ${{ inputs.es-user }}
ES_PASSWORD: ${{ inputs.es-password }}
KIBANA_URL: ${{ inputs.kibana-url }}
STACK_VERSION: ${{ inputs.elk-stack-version }}
AGENT_VERSION: ${{ inputs.elk-stack-version }}
run: |
poetry run python ./install_okta_integration.py

- name: Install Okta Entity Analytics (Fleet, Wiz agent policy)
id: okta-entityanalytics-integration
if: ${{ !cancelled() && steps.deploy-cdr-infra.outcome == 'success' && steps.wiz-integration.outcome == 'success' }}
working-directory: tests/integrations_setup
shell: bash
env:
OKTA_ENTITY_ANALYTICS_DOMAIN: ${{ inputs.okta-entity-analytics-domain }}
OKTA_API_KEY: ${{ inputs.okta-api-key }}
ES_USER: ${{ inputs.es-user }}
ES_PASSWORD: ${{ inputs.es-password }}
KIBANA_URL: ${{ inputs.kibana-url }}
STACK_VERSION: ${{ inputs.elk-stack-version }}
AGENT_VERSION: ${{ inputs.elk-stack-version }}
run: |
poetry run python ./install_entityanalytics_okta_integration.py

- name: Deploy WIZ agent
if: ${{ !cancelled() && steps.deploy-cdr-infra.outcome == 'success' && steps.wiz-integration.outcome == 'success' }}
if: ${{ !cancelled() && steps.deploy-cdr-infra.outcome == 'success' && steps.wiz-integration.outcome == 'success' }}
working-directory: deploy/test-environments/cdr
shell: bash
env:
Expand All @@ -277,6 +302,118 @@ runs:
cmd="chmod +x $scriptname && ./$scriptname"
../remote_setup.sh -k "$WIZ_KEY" -s "$src" -h "$WIZ_PUBLIC_IP" -d "~/$scriptname" -c "$cmd"

- name: Install Elastic Defend (Fleet)
id: elastic-defend-fleet
if: ${{ !cancelled() && steps.deploy-cdr-infra.outcome == 'success' }}
working-directory: tests/integrations_setup
shell: bash
env:
ES_USER: ${{ inputs.es-user }}
ES_PASSWORD: ${{ inputs.es-password }}
KIBANA_URL: ${{ inputs.kibana-url }}
STACK_VERSION: ${{ inputs.elk-stack-version }}
AGENT_VERSION: ${{ inputs.elk-stack-version }}
ELASTIC_DEFEND_ENROLL_LINUX: true
ELASTIC_DEFEND_ENROLL_WINDOWS: true
ELASTIC_DEFEND_LINUX_PUBLIC_IP: ${{ steps.generate-data.outputs.elastic-defend-linux-public-ip }}
ELASTIC_DEFEND_WINDOWS_PUBLIC_IP: ${{ steps.generate-data.outputs.elastic-defend-windows-public-ip }}
ELASTIC_DEFEND_WINDOWS_INSTANCE_ID: ${{ steps.generate-data.outputs.elastic-defend-windows-instance-id }}
run: |
poetry run python ./install_elastic_defend_integration.py

- name: Deploy Elastic Defend agent (Linux)
if: ${{ !cancelled() && steps.deploy-cdr-infra.outcome == 'success' && steps.elastic-defend-fleet.outcome == 'success' && steps.generate-data.outputs.elastic-defend-linux-public-ip != '' }}
working-directory: deploy/test-environments/cdr
shell: bash
env:
DEFEND_KEY: ${{ steps.generate-data.outputs.elastic-defend-linux-key }}
DEFEND_PUBLIC_IP: ${{ steps.generate-data.outputs.elastic-defend-linux-public-ip }}
run: |
scriptname="elastic-defend-linux.sh"
src="../../../tests/integrations_setup/$scriptname"
cmd="chmod +x $scriptname && ./$scriptname"
../remote_setup.sh -k "$DEFEND_KEY" -s "$src" -h "$DEFEND_PUBLIC_IP" -d "~/$scriptname" -c "$cmd"

# PEM path in Terraform output is relative to deploy/test-environments/cdr (same as terraform apply).
- name: Prepare Windows Defend credentials (WinRM)
id: windows-defend-credentials
if: ${{ !cancelled() && steps.deploy-cdr-infra.outcome == 'success' && steps.elastic-defend-fleet.outcome == 'success' && steps.generate-data.outputs.elastic-defend-windows-public-ip != '' }}
working-directory: deploy/test-environments/cdr
shell: bash
env:
AWS_DEFAULT_REGION: ${{ inputs.aws-region }}
DEFEND_WIN_KEY: ${{ steps.generate-data.outputs.elastic-defend-windows-key }}
DEFEND_WIN_INSTANCE: ${{ steps.generate-data.outputs.elastic-defend-windows-instance-id }}
DEFEND_WIN_IP: ${{ steps.generate-data.outputs.elastic-defend-windows-public-ip }}
WINDOWS_DEFEND_CREDENTIALS_FILE: "${{ github.workspace }}/tests/integrations_setup/.windows-defend-connection.json"
run: |
set -euo pipefail
echo "Waiting on ${DEFEND_WIN_IP}:5985 ..."
PORT_OK=""
for i in $(seq 1 12); do
if timeout 5 bash -c "echo > /dev/tcp/${DEFEND_WIN_IP}/5985" 2>/dev/null; then
PORT_OK=1
echo "Port is open"
break
fi
echo "attempt $i/12: sleeping 5s"
sleep 5
done
if [ -z "$PORT_OK" ]; then
echo "Timed out waiting for TCP 5985 on ${DEFEND_WIN_IP}"
exit 1
fi
if [ ! -f "$DEFEND_WIN_KEY" ]; then
echo "Windows PEM not found at DEFEND_WIN_KEY=$DEFEND_WIN_KEY (cwd=$(pwd); resolve paths from deploy/test-environments/cdr)"
exit 1
fi
PASSWORD=""
for j in $(seq 1 30); do
PASSWORD="$(aws ec2 get-password-data --region "$AWS_DEFAULT_REGION" --instance-id "$DEFEND_WIN_INSTANCE" --priv-launch-key "$DEFEND_WIN_KEY" --query PasswordData --output text || true)"
if [ -n "$PASSWORD" ] && [ "$PASSWORD" != "None" ]; then
break
fi
echo "Waiting for password ($j/30)..."
sleep 10
done
if [ -z "$PASSWORD" ] || [ "$PASSWORD" = "None" ]; then
echo "Failed to retrieve password"
exit 1
fi
echo "::add-mask::$PASSWORD"
export DEFEND_ADMIN_PASSWORD="$PASSWORD"
python3 <<'PY'
import json
import os
import pathlib

pathlib.Path(os.environ["WINDOWS_DEFEND_CREDENTIALS_FILE"]).write_text(
json.dumps(
{
"instance_id": os.environ["DEFEND_WIN_INSTANCE"],
"public_ip": os.environ["DEFEND_WIN_IP"],
"winrm_port": 5985,
"winrm_use_ssl": False,
"username": "Administrator",
"password": os.environ["DEFEND_ADMIN_PASSWORD"],
},
indent=2,
),
encoding="utf-8",
)
PY

- name: Enroll Elastic Defend agent (Windows WinRM)
if: ${{ !cancelled() && steps.windows-defend-credentials.outcome == 'success' }}
working-directory: tests/integrations_setup
shell: bash
env:
ELASTIC_DEFEND_WINDOWS_PS1: "${{ github.workspace }}/tests/integrations_setup/elastic-defend-windows.ps1"
WINDOWS_DEFEND_CREDENTIALS_FILE: "${{ github.workspace }}/tests/integrations_setup/.windows-defend-connection.json"
run: |
set -euo pipefail
poetry run python ./enroll_elastic_defend_winrm.py

- name: Check Asset Inventory supported version
id: asset-inventory-version-check
if: ${{ !cancelled() && steps.deploy-cdr-infra.outcome == 'success' }}
Expand All @@ -293,7 +430,7 @@ runs:
echo "asset_inventory_supported=false" >> $GITHUB_OUTPUT
fi

- name: Enable Entity Store
- name: Enable Entity Store (v1 or v2)
if: ${{ !cancelled() && steps.asset-inventory-version-check.outputs.asset_inventory_supported == 'true' }}
working-directory: tests/integrations_setup
shell: bash
Expand All @@ -302,8 +439,16 @@ runs:
ES_PASSWORD: ${{ inputs.es-password }}
KIBANA_URL: ${{ inputs.kibana-url }}
STACK_VERSION: ${{ inputs.elk-stack-version }}
ENABLE_ENTITY_STORE_V2: ${{ inputs.enable-entity-store-v2 }}
run: |
poetry run python ./enable_entity_store.py
set -euo pipefail
if [[ "${ENABLE_ENTITY_STORE_V2}" == "true" ]]; then
# Entity Store v2 prerequisites + install + maintainers + v2 status poll
poetry run python ./enable_entity_store_v2.py
else
# Entity Store v1 prerequisites + enable + v1 status poll (includes data view creation)
poetry run python ./enable_entity_store.py
fi

- name: Install Azure Asset Inventory integration
id: azure-asset-inventory-integration
Expand Down Expand Up @@ -413,5 +558,8 @@ runs:
EC2_ASSET_INV_KEY: ${{ steps.generate-data.outputs.ec2-asset-inv-key }}
EC2_WIZ_KEY: ${{ steps.generate-data.outputs.ec2-wiz-key }}
INTEGRATIONS_SETUP_DIR: "../../../tests/integrations_setup"
ELASTIC_DEFEND_LINUX_KEY: ${{ steps.generate-data.outputs.elastic-defend-linux-key }}
ELASTIC_DEFEND_WINDOWS_KEY: ${{ steps.generate-data.outputs.elastic-defend-windows-key }}
WINDOWS_DEFEND_CREDENTIALS_FILE: "${{ github.workspace }}/tests/integrations_setup/.windows-defend-connection.json"
run: |
./manage_infrastructure.sh "cdr" "upload-state"
6 changes: 6 additions & 0 deletions .github/actions/elk-stack/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ inputs:
default: "latest"
type: string
required: false
kibana-security-solution-experimental:
description: "ESS only: set Kibana user_settings_yaml for Security Solution experimental flags"
type: boolean
default: true
required: false
docker-image-version-override:
description: "Optional Docker image version to override the default stack image. Accepts formats like 8.x.y, 8.x.y-hash, or 8.x.y-SNAPSHOT."
type: string
Expand Down Expand Up @@ -79,6 +84,7 @@ runs:
TF_VAR_ess_region: ${{ inputs.ess-region }}
TF_VAR_ec_url: ${{ inputs.ec-url }}
TF_VAR_pin_version: ${{ inputs.docker-image-version-override }}
TF_VAR_kibana_security_solution_experimental: ${{ inputs.kibana-security-solution-experimental }}
TF_VAR_ec_api_key: ${{ inputs.ec-api-key }}
TF_VAR_deployment_template: ${{ env.TF_VAR_deployment_template }}
TF_VAR_max_size: ${{ env.TF_VAR_max_size }}
Expand Down
12 changes: 12 additions & 0 deletions .github/workflows/cdr-infra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ on:
description: "Number of days until environment expiration"
required: false
default: "5"
kibana_security_solution_experimental:
description: "ESS only: apply Kibana Security Solution experimental user settings (new home, watchlist)"
type: boolean
required: false
default: true
enable-entity-store-v2:
description: "CDR: when true run Entity Store v2; when false run Entity Store v1 only"
type: boolean
required: false
default: true

jobs:
init:
Expand Down Expand Up @@ -65,3 +75,5 @@ jobs:
serverless_mode: ${{ fromJSON(inputs.serverless_mode) }}
infra-type: ${{ needs.init.outputs.infra-type }}
expiration_days: ${{ inputs.expiration-days }}
kibana_security_solution_experimental: ${{ inputs.kibana_security_solution_experimental }}
enable-entity-store-v2: ${{ fromJSON(inputs.enable-entity-store-v2) }}
Loading
Loading