Skip to content
Open
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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,15 @@ The following table lists the _latest_ DSF Kit releases, their release date and
2. Improvements and bug fixes.
</td>
</tr>
<tr>
<td>TBD
</td>
<td>1.7.35</td>
<td>
1. Added support for Elastic IP (EIP) pool for AWS deployments. Set 'use_eip_pool' to true and specify 'eip_pool_tag' to use pre-allocated EIPs with predictable IP addresses.
<br/>2. Improvements and bug fixes.
</td>
</tr>

</table>

Expand Down
2 changes: 2 additions & 0 deletions examples/aws/poc/dsf_deployment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ Several variables in the `variables.tf` file are important for configuring the d

### Networking
- `subnet_ids`: IDs of the subnets for the deployment. If not specified, a new vpc is created.
- `use_eip_pool`: Set to `true` to use pre-allocated Elastic IPs from a pool instead of creating new ones. Default: `false`
- `eip_pool_tag`: AWS tag value to identify the EIP pool (e.g., `dsf-eip-pool`). Only used when `use_eip_pool = true`. EIPs must be tagged with `Pool=<eip_pool_tag>` in AWS before deployment.

### Audit Sources for Simulation Purposes
- `simulation_db_types_for_agentless`: Types of databases to provision and onboard to an Agentless Gateway
Expand Down
23 changes: 19 additions & 4 deletions examples/aws/poc/dsf_deployment/cm.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ locals {
}

module "ciphertrust_manager" {
source = "imperva/dsf-ciphertrust-manager/aws"
version = "1.7.34" # latest release tag
count = local.ciphertrust_manager_count
source = "imperva/dsf-ciphertrust-manager/aws"
version = "1.7.34" # latest release tag
count = local.ciphertrust_manager_count
ciphertrust_manager_version = var.ciphertrust_manager_version
ami = var.ciphertrust_manager_ami_id == null ? null : {
id = var.ciphertrust_manager_ami_id
Expand All @@ -20,6 +20,7 @@ module "ciphertrust_manager" {
subnet_id = local.ciphertrust_manager_subnet_id
cm_password = local.password
attach_persistent_public_ip = true
eip_allocation_id = length(local.ciphertrust_manager_eip_allocation_ids) > 0 ? local.ciphertrust_manager_eip_allocation_ids[count.index] : null
key_pair = module.key_pair.key_pair.key_pair_name
allowed_web_console_and_api_cidrs = concat(local.workstation_cidr, var.web_console_cidr)
allowed_ssh_cidrs = concat(local.workstation_cidr, var.allowed_ssh_cidrs)
Expand All @@ -33,7 +34,20 @@ module "ciphertrust_manager" {
]
}

# When using pooled EIPs, the public IP is known immediately but the association takes time
# Add a delay to ensure the EIP is associated before the provider tries to connect
resource "time_sleep" "wait_for_ciphertrust_eip" {
count = local.ciphertrust_manager_count > 0 && var.use_eip_pool ? 1 : 0

depends_on = [
module.ciphertrust_manager
]

create_duration = "30s"
}

provider "ciphertrust" {
# Use public IP for connectivity from local Mac/CI runners
address = local.ciphertrust_manager_count > 0 ? "https://${coalesce(module.ciphertrust_manager[0].public_ip, module.ciphertrust_manager[0].private_ip)}" : null
username = local.ciphertrust_manager_web_console_username
password = local.password
Expand All @@ -46,7 +60,8 @@ resource "ciphertrust_trial_license" "trial_license" {
flag = "activate"

depends_on = [
module.ciphertrust_manager
module.ciphertrust_manager,
time_sleep.wait_for_ciphertrust_eip # Ensure EIP is associated before connecting
]
}

Expand Down
1 change: 1 addition & 0 deletions examples/aws/poc/dsf_deployment/cte_ddc_agents.tf
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ module "cte_ddc_agents" {
}
os_type = each.value.os_type
attach_persistent_public_ip = true
eip_allocation_id = lookup(local.cte_agent_eip_allocation_ids, each.key, null)
use_public_ip = true
allowed_ssh_cidrs = concat(local.workstation_cidr, var.allowed_ssh_cidrs)
allowed_rdp_cidrs = each.value.os_type == "Windows" ? concat(local.workstation_cidr, var.allowed_ssh_cidrs) : []
Expand Down
1 change: 1 addition & 0 deletions examples/aws/poc/dsf_deployment/dam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module "mx" {
port = 8443
} : null
attach_persistent_public_ip = true
eip_allocation_id = local.mx_eip_allocation_id
large_scale_mode = var.large_scale_mode.mx

create_server_group = length(var.simulation_db_types_for_agent) > 0
Expand Down
4 changes: 2 additions & 2 deletions examples/aws/poc/dsf_deployment/dra.tf
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module "dra_admin" {
allowed_hub_cidrs = local.hub_cidr_list
allowed_ssh_cidrs = concat(local.workstation_cidr, var.allowed_ssh_cidrs)
attach_persistent_public_ip = true
eip_allocation_id = local.dra_admin_eip_allocation_id

tags = local.tags
depends_on = [
Expand All @@ -31,8 +32,7 @@ module "dra_admin" {
module "dra_analytics" {
source = "imperva/dsf-dra-analytics/aws"
version = "1.7.34" # latest release tag

count = local.dra_analytics_count
count = local.dra_analytics_count
name = join("-", [local.deployment_name_salted, "dra", "analytics", count.index])
subnet_id = local.dra_analytics_subnet_id
dra_version = module.globals.dra_version
Expand Down
108 changes: 108 additions & 0 deletions examples/aws/poc/dsf_deployment/eip_pool.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Query AWS for all EIPs in the pool
data "aws_eips" "pool" {
count = var.use_eip_pool ? 1 : 0

filter {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if there multiple deployment with the same eip_pool_tag competing for the same EIPs?
maybe we can document this limitation

name = "tag:Pool"
values = [var.eip_pool_tag]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know you wrote a comment that we expect the user to only give us unassociated ids, but maybe we can filter out already associated EIPs and catch user errors with validation instead of during runtime?

something like:
filter {
name = "association-id"
values = [""] # Empty association-id means unassociated
}

}
}

# Create locals to distribute allocation IDs to resources
locals {
# Get list of allocation IDs from pool (only unassociated ones to avoid conflicts)
eip_pool_all_allocation_ids = var.use_eip_pool ? data.aws_eips.pool[0].allocation_ids : []

# Calculate how many IPs we need
eip_count_needed = (
(var.enable_sonar ? 1 : 0) + # hub_main
(var.enable_sonar && var.hub_hadr ? 1 : 0) + # hub_dr
(var.enable_dam ? 1 : 0) + # mx
(var.enable_dra ? 1 : 0) + # dra_admin
(var.enable_ciphertrust ? var.ciphertrust_manager_count : 0) + # ciphertrust_managers
(var.enable_ciphertrust ? ( # cte/ddc agents
var.cte_ddc_agents_linux_count +
var.cte_agents_linux_count +
var.ddc_agents_linux_count +
var.cte_ddc_agents_windows_count +
var.cte_agents_windows_count +
var.ddc_agents_windows_count
) : 0)
)

# Validate we have enough IPs
eip_pool_valid = !var.use_eip_pool || length(local.eip_pool_all_allocation_ids) >= local.eip_count_needed

# Distribute allocation IDs to resources
# Use null if use_eip_pool is false (modules will create new EIPs)

# Index counter for distributing IPs
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we change the way we distribute the EIPs and make it more robust?
currently the calculated indices will shift whenever the deployment configuration changes.
this also applies to the CM agents map.
maybe we can keep a fixed and stable allocation.

hub_main_eip_index = 0
hub_dr_eip_index = var.enable_sonar ? 1 : 0
mx_eip_index = (var.enable_sonar ? 1 : 0) + (var.enable_sonar && var.hub_hadr ? 1 : 0)
dra_admin_eip_index = (
(var.enable_sonar ? 1 : 0) +
(var.enable_sonar && var.hub_hadr ? 1 : 0) +
(var.enable_dam ? 1 : 0)
)
ciphertrust_manager_eip_start_index = (
(var.enable_sonar ? 1 : 0) +
(var.enable_sonar && var.hub_hadr ? 1 : 0) +
(var.enable_dam ? 1 : 0) +
(var.enable_dra ? 1 : 0)
)
cte_agent_eip_start_index = (
(var.enable_sonar ? 1 : 0) +
(var.enable_sonar && var.hub_hadr ? 1 : 0) +
(var.enable_dam ? 1 : 0) +
(var.enable_dra ? 1 : 0) +
(var.enable_ciphertrust ? var.ciphertrust_manager_count : 0)
)

# Assign specific allocation IDs to each resource
hub_main_eip_allocation_id = var.use_eip_pool && var.enable_sonar ? local.eip_pool_all_allocation_ids[local.hub_main_eip_index] : null
hub_dr_eip_allocation_id = var.use_eip_pool && var.enable_sonar && var.hub_hadr ? local.eip_pool_all_allocation_ids[local.hub_dr_eip_index] : null
mx_eip_allocation_id = var.use_eip_pool && var.enable_dam ? local.eip_pool_all_allocation_ids[local.mx_eip_index] : null
dra_admin_eip_allocation_id = var.use_eip_pool && var.enable_dra ? local.eip_pool_all_allocation_ids[local.dra_admin_eip_index] : null

# For CipherTrust Managers, create a list of allocation IDs
ciphertrust_manager_eip_allocation_ids = var.use_eip_pool && var.enable_ciphertrust ? [
for i in range(var.ciphertrust_manager_count) :
local.eip_pool_all_allocation_ids[local.ciphertrust_manager_eip_start_index + i]
] : []

# For CTE/DDC agents, create a map of allocation IDs keyed by agent ID
# This matches the structure of local.all_agent_instances_map from cte_ddc_agents.tf
cte_agent_eip_allocation_ids = var.use_eip_pool && var.enable_ciphertrust ? {
for idx, instance_id in keys(local.all_agent_instances_map) :
instance_id => local.eip_pool_all_allocation_ids[local.cte_agent_eip_start_index + idx]
} : {}
}

# Validation check
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we can check in here that the EIPs' availability and not just quantity, checking there are all unassociated and logging the result to the user.

resource "null_resource" "eip_pool_validation" {
count = var.use_eip_pool ? 1 : 0

lifecycle {
precondition {
condition = local.eip_pool_valid
error_message = <<EOF
EIP Pool Error: Not enough IPs in pool!
Pool tag: ${var.eip_pool_tag}
IPs available: ${length(local.eip_pool_all_allocation_ids)}
IPs needed: ${local.eip_count_needed}

Breakdown of IPs needed:
- Hub Main: ${var.enable_sonar ? 1 : 0}
- Hub DR: ${var.enable_sonar && var.hub_hadr ? 1 : 0}
- MX: ${var.enable_dam ? 1 : 0}
- DRA Admin: ${var.enable_dra ? 1 : 0}
- CipherTrust Managers: ${var.enable_ciphertrust ? var.ciphertrust_manager_count : 0}
- CTE/DDC Agents: ${var.enable_ciphertrust ? (var.cte_ddc_agents_linux_count + var.cte_agents_linux_count + var.ddc_agents_linux_count + var.cte_ddc_agents_windows_count + var.cte_agents_windows_count + var.ddc_agents_windows_count) : 0}

Please allocate more EIPs with tag Pool=${var.eip_pool_tag}:
aws ec2 allocate-address --domain vpc --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Pool,Value=${var.eip_pool_tag}}]'
EOF
}
}
}
2 changes: 2 additions & 0 deletions examples/aws/poc/dsf_deployment/sonar.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module "hub_main" {
ebs = var.hub_ebs_details
instance_type = var.hub_instance_type
attach_persistent_public_ip = true
eip_allocation_id = local.hub_main_eip_allocation_id
use_public_ip = true
generate_access_tokens = true
ssh_key_pair = {
Expand Down Expand Up @@ -80,6 +81,7 @@ module "hub_dr" {
ebs = var.hub_ebs_details
instance_type = var.hub_instance_type
attach_persistent_public_ip = true
eip_allocation_id = local.hub_dr_eip_allocation_id
use_public_ip = true
hadr_dr_node = true
main_node_sonarw_public_key = module.hub_main[0].sonarw_public_key
Expand Down
25 changes: 25 additions & 0 deletions examples/aws/poc/dsf_deployment/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -494,4 +494,29 @@ variable "create_fam_classification_integration_resources" {
type = bool
default = false
description = "Whether to create the AWS S3 and SQS resources required for FAM classification integration between Hub and CipherTrust."
}

variable "use_eip_pool" {
type = bool
default = false
description = <<EOF
Whether to use pre-allocated Elastic IPs from a pool for all resources.
When true, Terraform queries AWS for EIPs tagged with eip_pool_tag and distributes them to resources.
When false (default), Terraform creates and manages new EIPs.

IMPORTANT: Before setting to true, you must:
1. Manually create EIPs in AWS with the Pool tag
2. Ensure you have at least as many EIPs as resources that need them
3. Run: aws ec2 describe-addresses --filters "Name=tag:Pool,Values=<your-tag>"
EOF
}

variable "eip_pool_tag" {
type = string
default = "dsf-eip-pool"
description = <<EOF
The Pool tag value used to identify the EIP pool in AWS.
Only used when use_eip_pool = true.
Example: "dsf-eip-pool" will query for EIPs tagged with Pool=dsf-eip-pool
EOF
}
1 change: 1 addition & 0 deletions modules/aws/agent-gw/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ module "agent_gw" {
timeout = local.timeout
}
attach_persistent_public_ip = false
eip_allocation_id = var.eip_allocation_id
tags = var.tags
send_usage_statistics = var.send_usage_statistics
}
16 changes: 16 additions & 0 deletions modules/aws/agent-gw/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,22 @@ variable "gateway_group_name" {
}
}

variable "eip_allocation_id" {
type = string
default = null
description = <<EOF
Optional: Allocation ID of an existing Elastic IP to use instead of creating a new one.
When provided, Terraform will associate this EIP instead of creating a new one.
When null (default), Terraform creates and manages a new EIP (current behavior).
Example: "eipalloc-0123456789abcdef0"
EOF

validation {
condition = var.eip_allocation_id == null || can(regex("^eipalloc-[a-f0-9]{8,}$", var.eip_allocation_id))
error_message = "eip_allocation_id must be in format 'eipalloc-xxxxxxxxx' or null"
}
}

variable "tags" {
description = "A map of tags to add to all resources"
type = map(string)
Expand Down
1 change: 1 addition & 0 deletions modules/aws/agentless-gw/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ module "gw_instance" {
terraform_script_path_folder = var.terraform_script_path_folder
use_public_ip = var.use_public_ip
attach_persistent_public_ip = false
eip_allocation_id = var.eip_allocation_id
sonarw_private_key_secret_name = var.sonarw_private_key_secret_name
sonarw_public_key_content = var.sonarw_public_key_content
volume_attachment_device_name = var.volume_attachment_device_name
Expand Down
16 changes: 16 additions & 0 deletions modules/aws/agentless-gw/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,22 @@ variable "public_ip" {
description = "Create public IP for the instance"
}

variable "eip_allocation_id" {
type = string
default = null
description = <<EOF
Optional: Allocation ID of an existing Elastic IP to use instead of creating a new one.
When provided, Terraform will associate this EIP instead of creating a new one.
When null (default), Terraform creates and manages a new EIP (current behavior).
Example: "eipalloc-0123456789abcdef0"
EOF

validation {
condition = var.eip_allocation_id == null || can(regex("^eipalloc-[a-f0-9]{8,}$", var.eip_allocation_id))
error_message = "eip_allocation_id must be in format 'eipalloc-xxxxxxxxx' or null"
}
}

variable "use_public_ip" {
type = bool
default = false
Expand Down
37 changes: 29 additions & 8 deletions modules/aws/ciphertrust-manager/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,48 @@ locals {
[for sg in aws_security_group.sg : sg.id],
var.security_group_ids)

public_ip = (var.attach_persistent_public_ip ?
(length(aws_eip.dsf_instance_eip) > 0 ? aws_eip.dsf_instance_eip[0].public_ip : null) :
aws_instance.cipthertrust_manager_instance.public_ip)
public_dns = (var.attach_persistent_public_ip ?
(length(aws_eip.dsf_instance_eip) > 0 ? aws_eip.dsf_instance_eip[0].public_dns : null) :
aws_instance.cipthertrust_manager_instance.public_dns)
# Determine public IP/DNS based on whether using existing EIP or created EIP
public_ip = var.attach_persistent_public_ip ? (
var.eip_allocation_id != null ?
data.aws_eip.existing[0].public_ip : # From existing EIP
(length(aws_eip.dsf_instance_eip) > 0 ? aws_eip.dsf_instance_eip[0].public_ip : null) # From created EIP
) : aws_instance.cipthertrust_manager_instance.public_ip

public_dns = var.attach_persistent_public_ip ? (
var.eip_allocation_id != null ?
data.aws_eip.existing[0].public_dns :
(length(aws_eip.dsf_instance_eip) > 0 ? aws_eip.dsf_instance_eip[0].public_dns : null)
) : aws_instance.cipthertrust_manager_instance.public_dns

private_ip = length(aws_network_interface.eni.private_ips) > 0 ? tolist(aws_network_interface.eni.private_ips)[0] : null

cm_address = coalesce(local.public_ip, local.private_ip)

# Determine which allocation ID to use
eip_allocation_id = var.attach_persistent_public_ip ? (
var.eip_allocation_id != null ?
var.eip_allocation_id : # Use provided allocation ID
aws_eip.dsf_instance_eip[0].id # Use created EIP
) : null
}

# Data source to lookup existing EIP (when allocation ID provided)
data "aws_eip" "existing" {
count = var.attach_persistent_public_ip && var.eip_allocation_id != null ? 1 : 0
id = var.eip_allocation_id
}

# Create new EIP (only when allocation ID NOT provided)
resource "aws_eip" "dsf_instance_eip" {
count = var.attach_persistent_public_ip ? 1 : 0
count = var.attach_persistent_public_ip && var.eip_allocation_id == null ? 1 : 0
domain = "vpc"
tags = merge(var.tags, { Name = var.friendly_name })
}

resource "aws_eip_association" "eip_assoc" {
count = var.attach_persistent_public_ip ? 1 : 0
instance_id = aws_instance.cipthertrust_manager_instance.id
allocation_id = aws_eip.dsf_instance_eip[0].id
allocation_id = local.eip_allocation_id
}

resource "aws_instance" "cipthertrust_manager_instance" {
Expand Down
Loading