Files
fleet-terraform/example/main.tf
T

367 lines
14 KiB
Terraform

# This example doesn't cover using a remote backend for storing the current
# terraform state in S3 with a lock in DynamoDB (ideal for AWS) or other
# methods. If using automation to apply the configuration or if multiple people
# will be managing these resources, this is recommended.
#
# See https://developer.hashicorp.com/terraform/language/settings/backends/s3
# for reference.
terraform {
required_version = ">= 1.12.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 6.37.0"
}
}
}
# Configure the AWS Provider
provider "aws" {
region = "us-east-2"
}
locals {
# Change these to match your environment. Create or use a fully
# qualified domain (fqdn) and a VPC in AWS.
domain_name = "fleet.example.com"
vpc_name = "fleet-vpc"
# This creates a subdomain in AWS to manage DNS Records.
# This allows for easy validation of TLS Certificates via ACM and
# the use of alias records to the load balancer. Please note if
# this is a subdomain that NS records will be needed to be created
# in the primary zone. These NS records will be included in the outputs
# of this terraform run.
zone_name = "fleet.example.com"
# Bucket names need to be unique across AWS. Change this to a friendly
# name to make finding carves in s3 easier later. Uncomment if using
# s3 carves.
# osquery_carve_bucket_name = "fleet-osquery-carve"
# Uncomment if using Firehose logging destinations.
# osquery_results_bucket_name = "fleet-osquery-results"
# osquery_status_bucket_name = "fleet-osquery-status"
# Extra ENV Vars for Fleet customization can be set here.
fleet_environment_variables = {
# Uncomment and provide license key to unlock premium features.
# FLEET_LICENSE_KEY = "<enter_license_key>"
# JSON logging improves the experience with Cloudwatch Log Insights
FLEET_LOGGING_JSON = "true"
FLEET_MYSQL_MAX_OPEN_CONNS = "10"
FLEET_MYSQL_READ_REPLICA_MAX_OPEN_CONNS = "10"
# Vulnerabilities is a premium feature.
# Uncomment as this is a writable location in the container.
# FLEET_VULNERABILITIES_DATABASES_PATH = "/home/fleet"
FLEET_REDIS_MAX_OPEN_CONNS = "500"
FLEET_REDIS_MAX_IDLE_CONNS = "500"
}
# Used in the optional allowlist below
# Import allowlist from text file
# allowlist_cidrs = split("\n", chomp(file("${path.module}/allowlist.txt")))
# Only 5 IPs allowed per rule
# https_listener_rules = [for i in range(0, length(local.allowlist_cidrs), 5) : {
# priority = i / 5 + 5
# actions = [{
# type = "forward"
# target_group_index = 0
# }]
# conditions = [{
# source_ips = slice(local.allowlist_cidrs, i, min(i + 5, length(local.allowlist_cidrs)))
# }]
# }]
}
module "fleet" {
source = "github.com/fleetdm/fleet-terraform?depth=1&ref=tf-mod-root-v1.30.0"
certificate_arn = module.acm.acm_certificate_arn
vpc = {
# By default, Availabililty zones for us-east-2 are configured. If an alternative region is desired,
# configure the azs (3 required) variable below to the desired region. If you have an exported AWS-REGION or a
# region declared in ~/.aws/config, this value must match the region declared below.
name = local.vpc_name
# azs = ["ca-central-1a", "ca-central-1b", "ca-central-1d"]
}
fleet_config = {
# To avoid pull-rate limiting from dockerhub, consider using our quay.io mirror
# for the Fleet image. e.g. "quay.io/fleetdm/fleet:v4.67.0"
image = "fleetdm/fleet:v4.90.0" # override default to deploy the image you desire
# See https://fleetdm.com/docs/deploy/reference-architectures#aws for appropriate scaling
# memory and cpu.
autoscaling = {
min_capacity = 2
max_capacity = 5
}
# 4GB Required for vulnerability scanning. 512MB works without.
mem = 4096
cpu = 512
extra_environment_variables = merge(
local.fleet_environment_variables,
# uncomment if using s3 carves
# module.osquery-carve.fleet_extra_environment_variables
# uncomment if using firehose
# module.firehose-logging.fleet_extra_environment_variables
)
extra_secrets = merge(
module.mdm.extra_secrets,
)
extra_execution_iam_policies = concat(
module.mdm.extra_execution_iam_policies,
)
# extra_iam_policies = concat(
# uncomment if using a3 carves
# module.osquery-carve.fleet_extra_iam_policies,
# uncomment if using firehose
# module.firehose-logging.fleet_extra_iam_policies,
# )
}
rds_config = {
# See https://fleetdm.com/docs/deploy/reference-architectures#aws for instance classes.
instance_class = "db.t4g.medium"
# Prevents edge case render failure in Audit log on the home screen.
db_parameters = {
# 8mb up from 262144 (256k) default
sort_buffer_size = 8388608
}
# Uncomment to specify the RDS engine version
# engine_version = "8.0.mysql_aurora.3.08.2"
# Uncomment to use more or fewer replicas
# replicas = 2
}
redis_config = {
# See https://fleetdm.com/docs/deploy/reference-architectures#aws for instance types.
instance_type = "cache.t4g.small"
# Note these parameters help performance with large/complex live queries.
# See https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Troubleshooting-live-queries.md#1-redis for details.
parameter = [
{ name = "client-output-buffer-limit-pubsub-hard-limit", value = 0 },
{ name = "client-output-buffer-limit-pubsub-soft-limit", value = 0 },
{ name = "client-output-buffer-limit-pubsub-soft-seconds", value = 0 },
]
}
alb_config = {
# Script execution can run for up to 300s plus overhead.
# Ensure the load balancer does not 5XX before we have results.
idle_timeout = 905
# Optionally change the primary Fleet target group from the default HTTP backend
# to HTTPS when Fleet itself terminates TLS on the ECS task.
# fleet_target_group = {
# protocol = "HTTPS"
# port = 8080
# }
# Optionally deploy load balancer as an internal load balancer
# internal = true
# optionally set deletion protection on (true) or off (false)
# enable_deletion_protection = true
# Optionally Remove X-Forwarded-For header
# xff_header_processing_mode = "remove"
# See https://github.com/terraform-aws-modules/terraform-aws-alb/blob/v9.17.0/examples/complete-alb/main.tf#L383-L393.
# All listener configs on the https listener can be overridden, but the following are the primary intent to be configurable.
# https_overrides = {
# routing_http_response_server_enabled = false
# routing_http_response_strict_transport_security_header_value = "max-age=31536000; includeSubDomains; preload"
# routing_http_response_access_control_allow_origin_header_value = "https://example.com"
# routing_http_response_access_control_allow_methods_header_value = "TRACE,GET"
# routing_http_response_access_control_allow_headers_header_value = "Accept-Language,Content-Language"
# routing_http_response_access_control_allow_credentials_header_value = "true"
# routing_http_response_access_control_expose_headers_header_value = "Cache-Control"
# routing_http_response_access_control_max_age_header_value = 86400
# routing_http_response_content_security_policy_header_value = "*"
# routing_http_response_x_content_type_options_header_value = "nosniff"
# routing_http_response_x_frame_options_header_value = "SAMEORIGIN"
# }
# Optional rules to allowlist only osquery/orbit traffic and allowed IPs.
# For https_listener_rules, the following conditions are supported
# Example:
# conditions = [{
# host_headers = ["example.com"]
# path_patterns = ["/api/*"]
# http_request_methods = ["GET", "POST"]
# source_ips = ["1.2.3.4/32"]
# http_headers = [{
# http_header_name = "X-Custom-Header-Foo"
# values = ["bar"]
# }]
# query_strings = [{
# key = "env"
# value = "foobar"
# }]
# }]
#
# https_listener_rules = concat([{
# priority = 9000
# actions = [{
# type = "fixed-response"
# content_type = "text/html"
# status_code = "403"
# message_body = "<h1><center>403 Forbidden</center></h1>"
# }]
# conditions = [{
# path_patterns = ["*"]
# }]
# }, {
# priority = 8999
# actions = [{
# type = "fixed-response"
# content_type = "text/html"
# status_code = "404"
# message_body = "<h1><center>404 Not Found</center></h1>"
# }]
# conditions = [{
# path_patterns = [
# "/version"
# ]
# }]
# }, {
# priority = 1
# actions = [{
# type = "forward"
# target_group_index = 0
# }]
# conditions = [{
# path_patterns = [
# "/api/osquery/*",
# "/api/*/osquery/*",
# "/api/*/orbit/*",
# ]
# }]
# }, {
# priority = 2
# actions = [{
# type = "forward"
# target_group_index = 0
# }]
# conditions = [{
# path_patterns = [
# "/api/*/fleet/device/*",
# "/mdm/*",
# "/api/mdm/apple/enroll",
# ]
# }]
# }, {
# priority = 3
# actions = [{
# type = "forward"
# target_group_index = 0
# }]
# conditions = [{
# path_patterns = [
# "/device/*",
# "/api/*/fleet/mdm/*",
# "/assets/*",
# ]
# }]
# }, {
# priority = 4
# actions = [{
# type = "forward"
# target_group_index = 0
# }]
# conditions = [{
# path_patterns = [
# "/api/mdm/microsoft/*",
# "/api/fleet/device/ping"
# ]
# }]
# }], local.https_listener_rules)
}
}
# Migrations will handle scaling Fleet to 0 running containers before running the DB migration task.
# This module will also handle scaling back up once migrations complete.
# NOTE: This requires the aws cli to be installed on the device running terraform as terraform
# doesn't directly support all the features required. the aws cli is invoked via a null-resource.
module "migrations" {
source = "github.com/fleetdm/fleet-terraform/addons/migrations?depth=1&ref=tf-mod-addon-migrations-v2.3.0"
ecs_cluster = module.fleet.byo-vpc.byo-db.byo-ecs.service.cluster
task_definition = module.fleet.byo-vpc.byo-db.byo-ecs.task_definition.family
task_definition_revision = module.fleet.byo-vpc.byo-db.byo-ecs.task_definition.revision
subnets = module.fleet.byo-vpc.byo-db.byo-ecs.service.network_configuration[0].subnets
security_groups = module.fleet.byo-vpc.byo-db.byo-ecs.service.network_configuration[0].security_groups
ecs_service = module.fleet.byo-vpc.byo-db.byo-ecs.service.name
desired_count = module.fleet.byo-vpc.byo-db.byo-ecs.appautoscaling_target.min_capacity
min_capacity = module.fleet.byo-vpc.byo-db.byo-ecs.appautoscaling_target.min_capacity
max_capacity = module.fleet.byo-vpc.byo-db.byo-ecs.appautoscaling_target.max_capacity
depends_on = [
module.fleet,
]
}
# Enable if using s3 for carves
# module "osquery-carve" {
# source = "github.com/fleetdm/fleet-terraform/addons/osquery-carve?depth=1&ref=tf-mod-addon-osquery-carve-v1.4.0"
# osquery_carve_s3_bucket = {
# name = local.osquery_carve_bucket_name
# }
# }
# Uncomment if using firehose logging destination
# module "firehose-logging" {
# source = "github.com/fleetdm/fleet-terraform/addons/logging-destination-firehose?depth=1&ref=tf-mod-addon-logging-destination-firehose-v1.3.0"
# osquery_results_s3_bucket = {
# name = local.osquery_results_bucket_name
# }
# osquery_status_s3_bucket = {
# name = local.osquery_status_bucket_name
# }
# }
## MDM Secret payload
# See https://github.com/fleetdm/fleet-terraform/blob/tf-mod-addon-mdm-v2.0.0/addons/mdm/README.md#abm
# Per that document, both Windows and Mac will use the same SCEP secret under the hood. Currently only
# the Windows MDM secrets still use this as the all Mac MDM is managed via the Fleet UI and is therefore
# disabled in the module.
module "mdm" {
source = "github.com/fleetdm/fleet-terraform/addons/mdm?depth=1&ref=tf-mod-addon-mdm-v2.2.0"
apn_secret_name = null
scep_secret_name = "fleet-scep"
abm_secret_name = null
enable_apple_mdm = false
enable_windows_mdm = true
}
module "acm" {
source = "terraform-aws-modules/acm/aws"
version = "4.3.1"
domain_name = local.domain_name
# If you change the route53 zone to a data source this needs to become "data.aws_route53_zone.main.id"
zone_id = aws_route53_zone.main.id
wait_for_validation = true
}
# If you already are managing your zone in AWS in the same account,
# this resource could be swapped with a data source instead to
# read the properties of that resource.
resource "aws_route53_zone" "main" {
name = local.zone_name
}
resource "aws_route53_record" "main" {
# If you change the route53_zone to a data source this also needs to become "data.aws_route53_zone.main.id"
zone_id = aws_route53_zone.main.id
name = local.domain_name
type = "A"
alias {
name = module.fleet.byo-vpc.byo-db.alb.lb_dns_name
zone_id = module.fleet.byo-vpc.byo-db.alb.lb_zone_id
evaluate_target_health = true
}
}
# Ensure that these records are added to the parent DNS zone
# Delete this output if you switched the route53 zone above to a data source.
output "route53_name_servers" {
value = aws_route53_zone.main.name_servers
}