OpenObserve
Self hosted logs, metrics, and traces on Fargate behind an internal FIPS TLS ALB.
GovCloudFIPSCMKView source
- Module
- openobserve
- Layer
- Observability
- Interface
- 39 inputs, 8 outputs
- Used by
- No apps yet
Why it matters
Teams need to search logs and traces without shipping data to a third party service that a federal customer has not approved. This module runs OpenObserve inside the VPC, stores telemetry in an S3 bucket the account owns, and ships with FIPS TLS, vendor telemetry turned off, and 90 day log retention.
Use it when
- A federal or air gapped deployment needs log search that stays inside the account.
- You want to route app logs through Fluent Bit with ecs-service's main_container_log_configuration.
Reach for something else when
- CloudWatch Logs from ecs-service is enough. It needs no extra infrastructure. Use ecs-service.
- You want browser side performance and error data. Use rum.
What it creates
aws_ecs_task_definitionand aws_ecs_service (OpenObserve plus a NATS coordinator)aws_lb,aws_lb_target_group, and HTTPS and HTTP redirect listeners (internal by default)aws_security_group(load balancer and task) with rulesaws_s3_bucketfor telemetry (versioning, encryption, public access block, lifecycle)aws_iam_role(task and execution, partition aware policy ARN)aws_cloudwatch_log_group(encrypted with the required kms_key_arn)aws_route53_record(A record in a private hosted zone)
Secure by default
- The load balancer is internal (alb_internal = true) and uses ELBSecurityPolicy-TLS13-1-2-FIPS-2023-04.
- The log group requires a customer managed key (kms_key_arn has no default).
- OpenObserve telemetry to the vendor is off (telemetry_enabled = false).
- The image is pinned to a release tag, never latest.
- Logs and telemetry are kept for 90 days, and the telemetry bucket refuses force deletion.
Commercial and GovCloud
module "openobserve" {
source = "git::ssh://git@github.com/the-kaizen-labs/terraform-modules.git//openobserve?ref=v1.7.0"
name_prefix = local.app_name
vpc_id = module.networking.vpc_id
private_subnet_ids = module.networking.private_subnet_ids
alb_subnet_ids = module.networking.private_subnet_ids
ecs_cluster_id = module.ecs_cluster.cluster_id
kms_key_arn = aws_kms_key.this.arn
certificate_arn = local.certificate_arn
private_hosted_zone_id = local.private_zone_id
parent_domain = "internal.example.com"
metadata_postgres_dsn_ssm_arn = aws_ssm_parameter.o2_meta_db_dsn.arn
admin_email = "devops@example.com"
admin_password_ssm_arn = local.o2_admin_password_arn
caller_ingress_security_group_ids = [module.ecs_service.security_group_id]
tags = local.tags
}| Setting | Commercial default | Federal setting | Note |
|---|---|---|---|
ssl_policy | ELBSecurityPolicy-TLS13-1-2-FIPS-2023-04 | ELBSecurityPolicy-TLS13-1-2-FIPS-2023-04 | FIPS 140-3 TLS is the default here. |
s3_kms_key_arn | null (AES256) | customer managed KMS key ARN | FedRAMP SC-13 and SC-28. |
log_retention_days | 90 | 90 or more | FedRAMP AU-11. |
s3_endpoint_url | null (https://s3.<region>.amazonaws.com) | https://s3-fips.<region>.amazonaws.com in commercial FedRAMP, the partition endpoint in GovCloud | |
telemetry_enabled | false | false |
How it connects
- From networking: vpc_id, private_subnet_ids
- From ecs-cluster: cluster_id (as ecs_cluster_id)
- From rds-postgres: db_host, in the SSM DSN passed as metadata_postgres_dsn_ssm_arn
- From ecs-service: security_group_id (as caller_ingress_security_group_ids)
- To ecs-service: ingest_host, for Fluent Bit log routing
- To rds-postgres: task_security_group_id (as allowed_security_group_ids)
Inputs
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
admin_email | string | yes | Initial OpenObserve root user email. | |
admin_password_ssm_arn | string | yes | SSM SecureString ARN holding the OpenObserve root user password. Caller creates this out-of-band. | |
alb_subnet_ids | list(string) | yes | Subnets for the ALB. | |
certificate_arn | string | yes | ACM certificate ARN covering the OpenObserve host. | |
ecs_cluster_id | string | yes | ECS cluster ID. | |
kms_key_arn | string | yes | CMK ARN for CloudWatch logs and Secrets Manager secrets. | |
metadata_postgres_dsn_ssm_arn | string | yes | SSM SecureString ARN holding the full Postgres DSN for OpenObserve metadata. Caller manages the RDS instance and SSM parameter. | |
name_prefix | string | yes | Resource name prefix. Used for every resource name and as the DNS label. | |
parent_domain | string | yes | Parent domain. Full DNS record defaults to <name_prefix>-o2.<parent_domain> unless hostname overrides it. | |
private_hosted_zone_id | string | yes | Route53 private hosted zone ID for the internal A-record. | |
private_subnet_ids | list(string) | yes | Private subnets for the OpenObserve Fargate task. | |
vpc_id | string | yes | VPC ID. | |
alb_internal | bool | true | no | If true, the ALB is internal-only. Set false for dev envs without VPN access. |
allowed_ingress_cidrs | list(string) | [] | no | CIDRs allowed to reach the ALB on 443. |
caller_ingress_security_group_ids | list(string) | [] | no | Security groups allowed to reach the ALB on 443 (e.g. app task SGs for firelens). |
cpu_architecture | string | "ARM64" | no | Task CPU architecture (X86_64 or ARM64). |
desired_count | number | 1 | no | ECS service desired_count. Default 1 (single-node OO). For an HA cluster set this >=3 alongside nats_replicas. |
hostname | string | null | no | Optional full FQDN for the OpenObserve UI/ingest endpoint. When null (default), the module composes <name_prefix>-o2.<parent_domain>. Set to override the -o2 suffix when you want a custom hostname like obs.example.com. Must still be under parent_domain (the Route53 record is created in the zone passed via private_hosted_zone_id). |
image | string | "public.ecr.aws/zinclabs/openobserve:v0.80.3" | no | OpenObserve container image. |
keycloak_oidc_client_id | string | null | no | Keycloak OIDC client_id. |
keycloak_oidc_client_secret_ssm_arn | string | null | no | SSM ARN holding the OIDC client secret. |
keycloak_oidc_enabled | bool | false | no | Toggle OpenObserve Enterprise + Dex-backed Keycloak SSO. |
keycloak_oidc_group_attribute | string | "groups" | no | OIDC claim carrying groups -> OpenObserve teams. |
keycloak_oidc_issuer | string | null | no | Keycloak realm issuer URL. |
keycloak_oidc_role_attribute | string | "roles" | no | OIDC claim carrying roles -> OpenObserve roles. |
keycloak_oidc_scopes | string | "openid profile email groups" | no | OIDC scopes (space-delimited). |
log_retention_days | number | 90 | no | CloudWatch log retention. FedRAMP AU-11 requires >=90. |
nats_image | string | "public.ecr.aws/docker/library/nats:2.10-alpine" | no | NATS image used as OpenObserve's cluster coordinator. |
nats_replicas | number | 1 | no | ZO_NATS_REPLICAS. Default 1 (single-node OO). For an HA cluster set this >=3 alongside desired_count. |
platform_version | string | "1.4.0" | no | Fargate platform version. |
s3_endpoint_url | string | null | no | Override for ZO_S3_SERVER_URL. When null (default), the module composes 'https://s3.<region>.amazonaws.com' (commercial AWS, non-FIPS). For FedRAMP commercial pass 'https://s3-fips.<region>.amazonaws.com'; for GovCloud pass the partition-appropriate endpoint. |
s3_force_destroy | bool | false | no | If true, terraform destroy auto-empties the telemetry bucket (versions + delete markers + current objects) before deleting it. Default false (federal-safe). Set true for dev/POC envs where you genuinely want to nuke the bucket without leaving an orphan. |
s3_kms_key_arn | string | null | no | Optional CMK ARN for telemetry bucket SSE. When null (default), the bucket uses AES256. Set for FedRAMP/GovCloud (SC-13/SC-28). Note: flipping this on an existing bucket only encrypts new objects; existing AES256 objects are not rewritten. |
s3_retention_days | number | 90 | no | Telemetry retention in S3 before lifecycle expiration. |
ssl_policy | string | "ELBSecurityPolicy-TLS13-1-2-FIPS-2023-04" | no | ALB SSL policy. Defaults to FIPS 140-3 TLS 1.3. |
tags | map(string) | {} | no | Tags applied to all resources. |
task_cpu | string | "1024" | no | Task-level CPU units. |
task_memory | string | "2048" | no | Task-level memory in MiB. |
telemetry_enabled | bool | false | no | ZO_TELEMETRY. Default false. OO phones home to ZincObserve when true, which is a non-starter for federal/air-gapped deployments. Flip to true only for commercial dev envs where you want to help upstream. |
Outputs
| Name | Description |
|---|---|
alb_dns_name | DNS name of the ALB. |
alb_security_group_id | SG attached to the ALB. |
alb_zone_id | Route53 hosted zone ID of the ALB. |
ingest_host | Hostname for OTLP / firelens ingest. Same host as the UI. |
otlp_http_endpoint | OTLP HTTP ingest endpoint (same host as the UI; routed by path). |
s3_bucket | Telemetry bucket. |
task_security_group_id | SG attached to the OpenObserve task. |
ui_url | Internal UI URL. |
Used by
No Kaizen app uses this module yet.