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
2 changes: 1 addition & 1 deletion database-monitoring/terraform/.module.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[module]
name = "aws-elastio-database-monitoring-agent"
version = "0.2.0"
version = "0.2.1"

description = "Terraform module that runs the Elastio database monitoring agent on AWS Fargate"
type = "terraform"
8 changes: 4 additions & 4 deletions database-monitoring/terraform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@ A security group with the usual allow-all egress already allows all three. The d
- a task-role policy that allows `elasticfilesystem:ClientMount` and `ClientWrite` on the file system, only through that access point.
- a file system policy that refuses anonymous clients and denies every mount that does not use that access point or TLS. Other roles in the account with their own EFS permissions can still mount through the access point if the network admits them, so keep `security_group_ids` for the agent only.
- A Fargate task definition of `task_cpu` and `task_memory` (by default 0.25 vCPU and 0.5 GB), ARM64, with a read-only root filesystem. The task runs as the image's non-root user, with `GOMEMLIMIT` set to 80% of the agent's memory: `task_memory`, less 384 MiB with `content_analysis = true`.
- With `content_analysis = true`, a second container in the same task, running Elastio's encryption detector (`ed_image`) as the agent's non-root user. Its gRPC port is on loopback only. Its Prometheus metrics port, TCP 50052, listens on all interfaces of the task, so `security_group_ids` must not allow inbound traffic on it. The agent needs no inbound rules at all. It reads a task-local scratch volume at `/var/lib/elastio-dbmon-ed`, read-only; see **Content analysis** below.
- With `content_analysis = true`, a second container in the same task, running Elastio's encryption detector (`ed_image`) as the agent's non-root user. Its gRPC and metrics ports listen on loopback only. The agent needs no inbound rules at all. It reads a task-local scratch volume at `/var/lib/elastio-dbmon-ed`, read-only; see **Content analysis** below.
- A service with `desired_count = 1`. Its deployment policy (minimum healthy 0%, maximum 100%) stops the old task before it starts the new one. A replication slot allows only one consumer at a time, and the agent's state allows only one writer. Don't raise the maximum.

## Content analysis

When rows are rewritten in place and no rewrite limit is declared for the table, the agent can't tell a migration from an attacker encrypting the data: both look the same in the change stream. With `content_analysis = true`, Elastio's encryption detector (ED) runs beside the agent and settles it. If the new values are ciphertext, the window becomes a high-severity finding that names the encrypted columns.

- **Off by default.** It needs agent 0.1.7 or later and `task_memory` of at least 1024. ED takes 384 MiB of the task and the agent gets the rest, so with `task_memory = 1024` the agent has 640 MiB and a `GOMEMLIMIT` of 512 MiB.
- **Off by default.** It needs agent 0.1.7 or later (0.1.8 binds the detector's metrics port to loopback too) and `task_memory` of at least 1024. ED takes 384 MiB of the task and the agent gets the rest, so with `task_memory = 1024` the agent has 640 MiB and a `GOMEMLIMIT` of 512 MiB.
- **What it does with your data.** The agent samples the rewritten values in memory, at most 4 MiB. When a window closes, it writes the sample to task-local storage for ED to read and removes it once ED answers. Values never reach the agent's EFS state, its log, or Elastio. Only the verdict does, as part of the finding.
- **Where ED comes from.** `ed_image` is built for ARM64 and x86-64 from the ED version the agent release was tested with. Each module version defaults to the matching pair.
- **If ED stops.** The agent keeps running. The windows it judges in the meantime get no verdict, which can raise a finding and never withholds one. ECS restarts ED.
Expand Down Expand Up @@ -196,8 +196,8 @@ No modules.
| <a name="input_assign_public_ip"></a> [assign_public_ip](#input_assign_public_ip) | Give the task a public IP. Needed only when the subnets have no NAT gateway and the server URL is on the internet. | `bool` | `false` | no |
| <a name="input_content_analysis"></a> [content_analysis](#input_content_analysis) | Run Elastio's encryption detector beside the agent, so a table whose rows are overwritten with ciphertext is reported as a high-severity finding even where no rewrite limit is declared. The agent samples the rewritten values in memory and on task-local storage only, for the detector to read; only the verdict leaves the task. Needs agent 0.1.7 or later and task_memory of at least 1024. | `bool` | `false` | no |
| <a name="input_database_url"></a> [database_url](#input_database_url) | postgres:// URL of the database to watch, for a role with REPLICATION. Stored in Secrets Manager, never in the task definition. | `string` | n/a | yes |
| <a name="input_ed_image"></a> [ed_image](#input_ed_image) | Encryption detector image, used when content_analysis is true: Elastio's ED gRPC server, built for amd64 and arm64 from the elastio/ed commit the agent release pins. The default is the one released with the default agent image. | `string` | `"public.ecr.aws/elastio/elastio-database-monitoring-ed:0.1.7"` | no |
| <a name="input_image"></a> [image](#input_image) | Agent image. The default is the agent release this module version was tested with. Pin a version; :latest moves. Needs 0.1.5 or later: older agents read only the QUELL\_\* variable names. | `string` | `"public.ecr.aws/elastio/elastio-database-monitoring-agent:0.1.7"` | no |
| <a name="input_ed_image"></a> [ed_image](#input_ed_image) | Encryption detector image, used when content_analysis is true: Elastio's ED gRPC server, built for amd64 and arm64 from the elastio/ed commit the agent release pins. The default is the one released with the default agent image. | `string` | `"public.ecr.aws/elastio/elastio-database-monitoring-ed:0.1.8"` | no |
| <a name="input_image"></a> [image](#input_image) | Agent image. The default is the agent release this module version was tested with. Pin a version; :latest moves. Needs 0.1.5 or later: older agents read only the QUELL\_\* variable names. | `string` | `"public.ecr.aws/elastio/elastio-database-monitoring-agent:0.1.8"` | no |
| <a name="input_log_retention_days"></a> [log_retention_days](#input_log_retention_days) | How long CloudWatch keeps the agent's log. | `number` | `7` | no |
| <a name="input_name"></a> [name](#input_name) | What the product shows for this agent. Also the ECS cluster, service and task family name, sanitised to the characters ECS allows. | `string` | n/a | yes |
| <a name="input_persistent_ledger"></a> [persistent_ledger](#input_persistent_ledger) | Keep the agent's state on an encrypted EFS file system so it persists across task replacement. When false, the state is on the task's ephemeral storage and every replacement starts it empty. | `bool` | `true` | no |
Expand Down
10 changes: 3 additions & 7 deletions database-monitoring/terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,9 @@ locals {
# costs a window its verdict and nothing else -- the agent judges without
# one and says so -- and ECS restarts it.
#
# The gRPC port is bound to loopback, so only the agent reaches it. The
# Prometheus metrics port is NOT: ED's Python server starts it with
# start_http_server(port) and no address, so it listens on every interface
# of the task ENI whatever --host says (verified on the image, ED 624e66b;
# still so on ED master). It serves counters and timings, never values,
# and the task's security groups are what keep it in: they must not admit
# inbound TCP 50052. The agent needs no inbound rule at all.
# Both ports, gRPC and Prometheus metrics, are bound to loopback, so only
# the agent reaches them (ED from ce003e0, elastio/ed#42; earlier ED bound
# metrics to every interface). The agent needs no inbound rule at all.
ed_container = {
name = "${local.prefix}-ed"
image = var.ed_image
Expand Down
6 changes: 3 additions & 3 deletions database-monitoring/terraform/tests/module.tftest.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ run "names_and_image" {
error_message = "secrets must be named elastio-dbmon/<name>/..."
}
assert {
condition = strcontains(aws_ecs_task_definition.this.container_definitions, "\"image\":\"public.ecr.aws/elastio/elastio-database-monitoring-agent:0.1.7\"")
error_message = "the default image must be Elastio's public ECR image of agent 0.1.7, the first that can ask the encryption detector"
condition = strcontains(aws_ecs_task_definition.this.container_definitions, "\"image\":\"public.ecr.aws/elastio/elastio-database-monitoring-agent:0.1.8\"")
error_message = "the default image must be Elastio's public ECR image of agent 0.1.8"
}
}

Expand Down Expand Up @@ -328,7 +328,7 @@ run "content_analysis_runs_the_detector_beside_the_agent" {
error_message = "the scratch volume must be task-local, never EFS"
}
assert {
condition = strcontains(aws_ecs_task_definition.this.container_definitions, "elastio-database-monitoring-ed:0.1.7")
condition = strcontains(aws_ecs_task_definition.this.container_definitions, "elastio-database-monitoring-ed:0.1.8")
error_message = "the detector defaults to the image released with the default agent"
}
}
Expand Down
4 changes: 2 additions & 2 deletions database-monitoring/terraform/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ variable "security_group_ids" {
variable "image" {
description = "Agent image. The default is the agent release this module version was tested with. Pin a version; :latest moves. Needs 0.1.5 or later: older agents read only the QUELL_* variable names."
type = string
default = "public.ecr.aws/elastio/elastio-database-monitoring-agent:0.1.7"
default = "public.ecr.aws/elastio/elastio-database-monitoring-agent:0.1.8"
}

variable "content_analysis" {
Expand All @@ -77,7 +77,7 @@ variable "content_analysis" {
variable "ed_image" {
description = "Encryption detector image, used when content_analysis is true: Elastio's ED gRPC server, built for amd64 and arm64 from the elastio/ed commit the agent release pins. The default is the one released with the default agent image."
type = string
default = "public.ecr.aws/elastio/elastio-database-monitoring-ed:0.1.7"
default = "public.ecr.aws/elastio/elastio-database-monitoring-ed:0.1.8"
}

variable "task_cpu" {
Expand Down
Loading