Integration configuration for Azure and AWS Logs

Configure log forwarding from Azure and AWS CloudWatch to Dynatrace using Terraform.

AWS CloudWatch Logs example

AWS log forwarding enables the streaming of logs from Amazon CloudWatch into Dynatrace logs via an ActiveGate. For more details, refer to CloudWatch Logs.

Below is a Terraform configuration example for setting up the CloudWatch log forwarder.

variable "stack_name" {
type = string
description = "Dynatrace log forwarder name"
default = "dynatracelogs"
}
variable "dynatrace_environment_url" {
description = "URL to Dynatrace environment"
}
variable "dynatrace_api_key" {
description = "Dynatrace API key"
sensitive = true
}
variable "verify_ssl_target_active_gate" {
description = "Verify SSL certificate for target ActiveGate"
default = false
}
variable "max_log_content_length" {
description = "Maximum log content length"
default = 65536
}
variable "use_existing_active_gate" {
description = "Use existing ActiveGate"
default = true
}
variable "dynatrace_paas_token" {
description = "Dynatrace PaaS token"
sensitive = true
default = "dummyToken"
}
variable "tenant_id" {
description = "Tenant ID"
default = "not_provided"
}
variable "deploy_ag_with_vpc" {
type = bool
description = "Deploy ActiveGate with VPC"
default = false
}
data "aws_ssm_parameter" "latest_amazon_linux_ami_id" {
name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
}
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
data "aws_availability_zones" "available" {}
resource "aws_vpc" "vpc" {
count = var.deploy_ag_with_vpc ? 1 : 0
cidr_block = "172.31.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
}
resource "aws_subnet" "public_subnet" {
count = var.deploy_ag_with_vpc ? 1 : 0
vpc_id = aws_vpc.vpc[count.index].id
cidr_block = "172.31.1.0/27"
availability_zone = data.aws_availability_zones.available.names[0]
map_public_ip_on_launch = true
}
resource "aws_subnet" "private_subnet" {
count = var.deploy_ag_with_vpc ? 1 : 0
vpc_id = aws_vpc.vpc[count.index].id
availability_zone = data.aws_availability_zones.available.names[0]
cidr_block = "172.31.2.0/27"
map_public_ip_on_launch = false
}
resource "aws_internet_gateway" "igw" {
count = var.deploy_ag_with_vpc ? 1 : 0
vpc_id = aws_vpc.vpc[count.index].id
}
resource "aws_route_table" "public_route_table" {
count = var.deploy_ag_with_vpc ? 1 : 0
vpc_id = aws_vpc.vpc[count.index].id
}
resource "aws_route" "public_route_internet" {
count = var.deploy_ag_with_vpc ? 1 : 0
route_table_id = aws_route_table.public_route_table.*.id[count.index]
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw[count.index].id
}
resource "aws_route_table_association" "public_subnet_route_table_assoc" {
count = var.deploy_ag_with_vpc ? 1 : 0
subnet_id = aws_subnet.public_subnet[count.index].id
route_table_id = aws_route_table.public_route_table.*.id[count.index]
}
resource "aws_security_group" "security_group" {
count = var.deploy_ag_with_vpc ? 1 : 0
vpc_id = aws_vpc.vpc[count.index].id
description = "Allow ActiveGate ingress"
}
resource "aws_security_group_rule" "active_gate_inbound" {
count = var.deploy_ag_with_vpc ? 1 : 0
type = "ingress"
from_port = 9999
to_port = 9999
protocol = "tcp"
security_group_id = aws_security_group.security_group.*.id[count.index]
source_security_group_id = aws_security_group.security_group.*.id[count.index]
}
resource "aws_instance" "ec2_active_gate" {
count = var.use_existing_active_gate ? 0 : 1
ami = data.aws_ssm_parameter.latest_amazon_linux_ami_id.value
instance_type = "t3.small"
subnet_id = aws_subnet.public_subnet[count.index].id
security_groups = [aws_security_group.security_group[count.index].id]
tags = {
Name = "${var.stack_name}-active-gate"
}
user_data = <<-EOF
#!/bin/bash -xe
wget -O Dynatrace-ActiveGate-Linux-x86.sh "${var.dynatrace_environment_url}/api/v1/deployment/installer/gateway/unix/latest?arch=x86&flavor=default" --header="Authorization: Api-Token ${var.dynatrace_paas_token}"
wget https://ca.dynatrace.com/dt-root.cert.pem
( echo 'Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="--SIGNED-INSTALLER"'; echo ; echo ; echo '----SIGNED-INSTALLER' ; cat Dynatrace-ActiveGate-Linux-x86.sh ) | openssl cms -verify -CAfile dt-root.cert.pem > /dev/null
/bin/sh Dynatrace-ActiveGate-Linux-x86.sh
echo "[aws_monitoring]
aws_monitoring_enabled = false
[azure_monitoring]
azure_monitoring_enabled = false
[cloudfoundry_monitoring]
cloudfoundry_monitoring_enabled = false
[kubernetes_monitoring]
kubernetes_monitoring_enabled = false
[vmware_monitoring]
vmware_monitoring_enabled = false
[rpm]
rpm_enabled = false
[beacon_forwarder]
beacon_forwarder_enabled = false
[extension_controller]
extension_controller_enabled = false
[dbAgent]
dbAgent_enabled = false
[metrics_ingest]
metrics_ingest_enabled = false
[collector]
MSGrouter = false" >> /var/lib/dynatrace/gateway/config/custom.properties
systemctl restart dynatracegateway
touch /home/ec2-user/userdata-ag-installation-success
EOF
}
resource "aws_iam_role" "lambda_role" {
name = "${var.stack_name}-lambda-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
Action = "sts:AssumeRole"
}]
})
managed_policy_arns = [
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
]
inline_policy {
name = "cloudwatch_put_metric_data"
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "cloudwatch:PutMetricData"
Resource = "*"
}]
})
}
lifecycle {
ignore_changes = [managed_policy_arns, inline_policy]
}
}
resource "aws_lambda_function" "lambda" {
filename = "dynatrace-aws-log-forwarder-lambda.zip"
function_name = "${var.stack_name}-function"
role = aws_iam_role.lambda_role.arn
handler = "index.handler"
runtime = "python3.8"
memory_size = 256
timeout = 60
environment {
variables = {
DEBUG = false
DYNATRACE_API_KEY = var.dynatrace_api_key
DYNATRACE_ENV_URL = var.deploy_ag_with_vpc ? "https://${element(aws_instance.ec2_active_gate.*.private_ip, 0)}:9999/e/${var.tenant_id}" : var.dynatrace_environment_url
VERIFY_SSL = var.verify_ssl_target_active_gate
MAX_LOG_CONTENT_LENGTH = var.max_log_content_length
CLOUD_LOG_FORWARDER = "${data.aws_caller_identity.current.account_id}:${data.aws_region.current.name}:${var.stack_name}"
}
}
}
resource "aws_s3_bucket" "delivery_bucket" {
bucket = "${var.stack_name}-delivery-bucket"
force_destroy = true
}
resource "aws_s3_bucket_lifecycle_configuration" "example" {
bucket = aws_s3_bucket.delivery_bucket.id
rule {
id = "rule-1"
status = "Enabled"
expiration {
days = 7
}
}
}
resource "aws_s3_bucket_public_access_block" "delivery_bucket_access" {
bucket = aws_s3_bucket.delivery_bucket.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_iam_role" "delivery_stream_role" {
name = "${var.stack_name}-delivery-stream-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
Service = "firehose.amazonaws.com"
}
Action = "sts:AssumeRole"
}]
})
inline_policy {
name = "firehose_delivery_policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"s3:AbortMultipartUpload",
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:PutObject"
]
Resource = [
aws_s3_bucket.delivery_bucket.arn,
"${aws_s3_bucket.delivery_bucket.arn}/*"
]
}]
})
}
}
resource "aws_kinesis_firehose_delivery_stream" "firehose_log_streams" {
name = "${var.stack_name}-firehose-delivery-stream"
destination = "extended_s3"
extended_s3_configuration {
bucket_arn = aws_s3_bucket.delivery_bucket.arn
role_arn = aws_iam_role.delivery_stream_role.arn
buffering_interval = 60
buffering_size = 5
compression_format = "GZIP"
error_output_prefix = "error-"
prefix = "success-"
processing_configuration {
enabled = true
processors {
type = "Lambda"
parameters {
parameter_name = "LambdaArn"
parameter_value = aws_lambda_function.lambda.arn
}
}
}
}
}
resource "aws_iam_policy" "firehose_lambda_invocation_policy" {
name = "firehose_lambda_invocation_policy"
description = "Policy for Firehose Lambda invocation"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"lambda:InvokeFunction",
"lambda:GetFunctionConfiguration",
]
Resource = [
aws_lambda_function.lambda.arn,
]
}
]
})
}
resource "aws_iam_role_policy_attachment" "delivery_stream_role_lambda_policy_attachment" {
role = aws_iam_role.delivery_stream_role.name
policy_arn = aws_iam_policy.firehose_lambda_invocation_policy.arn
}
resource "aws_iam_role" "cloudwatch_logs_role" {
name = "${var.stack_name}-cloud-watch-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "logs.${data.aws_region.current.name}.amazonaws.com"
}
Action = "sts:AssumeRole"
}
]
})
description = "Role for subscription filters (to write to Firehose)"
}
resource "aws_iam_policy" "cloudwatch_logs_policy" {
name = "${var.stack_name}-cloud-watch-policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"firehose:PutRecord",
"firehose:PutRecordBatch",
]
Resource = aws_kinesis_firehose_delivery_stream.firehose_log_streams.arn
}
]
})
}
resource "aws_iam_role_policy_attachment" "cloudwatch_logs_policy_attachment" {
role = aws_iam_role.cloudwatch_logs_role.name
policy_arn = aws_iam_policy.cloudwatch_logs_policy.arn
}
resource "aws_cloudwatch_dashboard" "self_monitoring_dashboard" {
dashboard_name = "DynatraceLogForwarder-SelfMonitoring-${data.aws_region.current.name}-${var.stack_name}"
dashboard_body = jsonencode({
"widgets": [
{
"height": 6,
"width": 12,
"y": 6,
"x": 0,
"type": "metric",
"properties": {
"metrics": [
[ "DT/LogsStreaming", "Kinesis record age", "function_name", "${aws_lambda_function.lambda.function_name}", { "stat": "Minimum" } ],
[ "...", { "stat": "Average" } ],
[ "..." ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"stat": "Maximum",
"period": 60,
"liveData": true,
"setPeriodToTimeRange": true,
"legend": {
"position": "bottom"
},
"title": "Kinesis - record age"
}
},
{
"height": 6,
"width": 12,
"y": 18,
"x": 12,
"type": "metric",
"properties": {
"metrics": [
[ "DT/LogsStreaming", "Kinesis record.data decompressed size", "function_name", "${aws_lambda_function.lambda.function_name}" ],
[ "...", { "stat": "Average" } ],
[ "...", { "stat": "Maximum" } ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"stat": "Minimum",
"period": 60,
"title": "Kinesis - record.data decompressed size"
}
},
{
"height": 6,
"width": 12,
"y": 18,
"x": 0,
"type": "metric",
"properties": {
"metrics": [
[ "DT/LogsStreaming", "Kinesis record.data compressed size", "function_name", "${aws_lambda_function.lambda.function_name}" ],
[ "...", { "stat": "Average" } ],
[ "...", { "stat": "Maximum" } ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"stat": "Minimum",
"period": 60,
"title": "Kinesis - record.data compressed size"
}
},
{
"height": 6,
"width": 12,
"y": 24,
"x": 0,
"type": "metric",
"properties": {
"metrics": [
[ { "expression": "SEARCH('{AWS/Logs,FilterName,LogGroupName,DestinationType} FilterName=\"${var.stack_name}\" MetricName=\"ForwardedLogEvents\"', 'Sum', 60)", "id": "e1", "region": "${data.aws_region.current.name}" } ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"period": 300,
"stat": "Average",
"title": "Log Groups - log entries received from CloudWatch"
}
},
{
"height": 6,
"width": 12,
"y": 30,
"x": 12,
"type": "metric",
"properties": {
"metrics": [
[ { "expression": "SEARCH('{AWS/Logs,FilterName,LogGroupName,DestinationType} FilterName=\"${var.stack_name}\" MetricName=\"ForwardedBytes\"', 'Sum', 60)", "id": "e1", "region": "${data.aws_region.current.name}" } ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"period": 300,
"stat": "Average",
"title": "Log Groups - bytes received from CloudWatch"
}
},
{
"height": 6,
"width": 12,
"y": 30,
"x": 0,
"type": "metric",
"properties": {
"metrics": [
[ "DT/LogsStreaming", "Batches prepared", "function_name", "${aws_lambda_function.lambda.function_name}" ],
[ ".", "Batches delivered", ".", "." ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"stat": "Sum",
"period": 60,
"title": "Delivery - batches"
}
},
{
"height": 6,
"width": 12,
"y": 36,
"x": 0,
"type": "metric",
"properties": {
"metrics": [
[ "DT/LogsStreaming", "Log entries prepared", "function_name", "${aws_lambda_function.lambda.function_name}" ],
[ ".", "Log entries delivered", ".", "." ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"stat": "Sum",
"period": 60,
"title": "Delivery - log entries"
}
},
{
"height": 6,
"width": 12,
"y": 36,
"x": 12,
"type": "metric",
"properties": {
"metrics": [
[ "DT/LogsStreaming", "Data volume prepared", "function_name", "${aws_lambda_function.lambda.function_name}" ],
[ ".", "Data volume delivered", ".", "." ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"title": "Delivery - data volume",
"period": 60,
"stat": "Sum"
}
},
{
"height": 6,
"width": 12,
"y": 48,
"x": 0,
"type": "metric",
"properties": {
"metrics": [
[ { "expression": "SEARCH('{DT/LogsStreaming,function_name,status_code} function_name=\"${aws_lambda_function.lambda.function_name}\" MetricName=\"Requests status code count\"', 'Sum', 60)", "id": "e1", "region": "${data.aws_region.current.name}" } ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"title": "Requests - status codes",
"period": 300,
"stat": "Average"
}
},
{
"height": 6,
"width": 12,
"y": 42,
"x": 0,
"type": "metric",
"properties": {
"metrics": [
[ "DT/LogsStreaming", "Requests duration", "function_name", "${aws_lambda_function.lambda.function_name}", { "stat": "Minimum" } ],
[ "..." ],
[ "...", { "stat": "Maximum" } ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"period": 60,
"stat": "Average",
"title": "Requests - durations"
}
},
{
"height": 6,
"width": 12,
"y": 48,
"x": 12,
"type": "metric",
"properties": {
"metrics": [
[ { "expression": "SEARCH('{DT/LogsStreaming,function_name,type} function_name=\"${aws_lambda_function.lambda.function_name}\" MetricName=\"Issues\"', 'Sum', 60)", "id": "e1", "region": "${data.aws_region.current.name}" } ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"stat": "Sum",
"period": 60,
"title": "Delivery - issues"
}
},
{
"height": 6,
"width": 12,
"y": 42,
"x": 12,
"type": "metric",
"properties": {
"metrics": [
[ "DT/LogsStreaming", "Log attr trimmed", "function_name", "${aws_lambda_function.lambda.function_name}" ],
[ ".", "Log content trimmed", ".", "." ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"period": 60,
"title": "Logs - trimmed",
"stat": "Sum"
}
},
{
"height": 6,
"width": 12,
"y": 6,
"x": 12,
"type": "metric",
"properties": {
"metrics": [
[ "DT/LogsStreaming", "Log age min", "function_name", "${aws_lambda_function.lambda.function_name}", { "stat": "Minimum" } ],
[ "DT/LogsStreaming", "Log age avg", "function_name", "${aws_lambda_function.lambda.function_name}" ],
[ "DT/LogsStreaming", "Log age max", "function_name", "${aws_lambda_function.lambda.function_name}", { "stat": "Maximum" } ]
],
"view": "timeSeries",
"stacked": false,
"title": "Logs - age",
"region": "${data.aws_region.current.name}",
"period": 60,
"stat": "Average"
}
},
{
"height": 6,
"width": 12,
"y": 0,
"x": 0,
"type": "metric",
"properties": {
"view": "timeSeries",
"stacked": false,
"metrics": [
[ "AWS/Lambda", "Invocations", "FunctionName", "${aws_lambda_function.lambda.function_name}" ]
],
"region": "${data.aws_region.current.name}",
"title": "Lambda - invocations"
}
},
{
"height": 6,
"width": 12,
"y": 0,
"x": 12,
"type": "metric",
"properties": {
"view": "timeSeries",
"stacked": false,
"metrics": [
[ "AWS/Lambda", "Duration", "FunctionName", "${aws_lambda_function.lambda.function_name}" ]
],
"region": "${data.aws_region.current.name}",
"title": "Lambda - duration"
}
},
{
"height": 6,
"width": 12,
"y": 12,
"x": 12,
"type": "metric",
"properties": {
"metrics": [
[ "AWS/Lambda", "Errors", "FunctionName", "${aws_lambda_function.lambda.function_name}" ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"stat": "Sum",
"period": 60,
"title": "Lambda errors"
}
},
{
"height": 6,
"width": 12,
"y": 12,
"x": 0,
"type": "metric",
"properties": {
"metrics": [
[ "DT/LogsStreaming", "Kinesis record age", "function_name", "${aws_lambda_function.lambda.function_name}", { "label": "Kinesis records" } ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"stat": "SampleCount",
"period": 60,
"title": "Kinesis - records number"
}
},
{
"height": 6,
"width": 12,
"y": 24,
"x": 12,
"type": "metric",
"properties": {
"metrics": [
[ "DT/LogsStreaming", "Kinesis record.data decompressed size", "function_name", "${aws_lambda_function.lambda.function_name}" ]
],
"view": "timeSeries",
"stacked": false,
"region": "${data.aws_region.current.name}",
"stat": "Sum",
"period": 60,
"title": "Kinesis - sum record.data decompressed size"
}
}
]
})
}

Azure Logs example

Azure log forwarding enables the streaming of logs from Azure Event Hubs into Dynatrace Logs via an Azure Function App instance. For details, see Azure Logs.

Below is a Terraform configuration example for setting up the Azure log forwarder.

variable "forwarderName" {
type = string
description = "Dynatrace log forwarder name"
default = "dynatracelogs"
}
variable "targetUrl" {
type = string
description = "Dynatrace destination (ActiveGate) URL"
}
variable "targetPaasToken" {
type = string
description = "Dynatrace PaaS token"
sensitive = true
default = "dummyToken"
}
variable "targetAPIToken" {
type = string
description = "Dynatrace API token"
sensitive = true
}
variable "eventHubConnectionString" {
type = string
description = "Event hub connection string"
default = ""
}
variable "deployActiveGateContainer" {
type = bool
description = "Deploy ActiveGate"
default = false
}
variable "selfMonitoringEnabled" {
type = bool
description = "Send self-monitoring metrics to Azure? (true/false)"
default = false
}
variable "requireValidCertificate" {
type = bool
description = "Verify Dynatrace log ingest endpoint SSL certificate? (true/false)"
default = false
}
variable "filterConfig" {
type = string
description = "Filter config"
default = ""
}
variable "eventhubConnectionClientId" {
type = string
description = "MI user id"
default = ""
}
variable "eventhubConnectionCredentials" {
type = string
description = "Managed Identity"
default = ""
}
variable "eventhubConnectionFullyQualifiedNamespace" {
type = string
description = "Eventhub's host name"
default = ""
}
locals {
resourceGroupName = "${var.forwarderName}${random_string.random_id.result}-resource-group"
eventHubNamespace = "${local.forwarderNameShort}${random_string.random_id.result}"
eventHubName = "${var.forwarderName}${random_string.random_id.result}-ehub"
eventHubNamespaceAuthRule = "${var.forwarderName}${random_string.random_id.result}-ehubns-auth-rule"
dtHost = var.targetUrl
dtHostParts = split("/", var.targetUrl)
registryUser = can(index(local.dtHostParts, 2)) ? index(local.dtHostParts, 2) : split(".", local.dtHostParts[0])[0]
image = "${local.dtHost}/linux/activegate:latest"
networkProfileName = "${var.forwarderName}${random_string.random_id.result}networkProfile"
virtualNetworkName = "${var.forwarderName}${random_string.random_id.result}-vnet"
functionSubnetName = "functionapp"
containerSubnetName = "aci"
appServicePlan = "${var.forwarderName}${random_string.random_id.result}-plan"
functionName = "${var.forwarderName}${random_string.random_id.result}-function"
forwarderNameShort = substr(var.forwarderName, 0, 18)
storageAccountName = "${local.forwarderNameShort}${random_string.random_id.result}sa"
}
resource "random_string" "random_id" {
length = 4
special = false
upper = false
}
# ######################################################################################
# PREREQ
# ######################################################################################
resource "azurerm_resource_group" "rg" {
name = local.resourceGroupName
location = "East US"
}
resource "azurerm_eventhub_namespace" "ehubns" {
name = local.eventHubNamespace
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
sku = "Basic"
capacity = 2
tags = {
LogsForwarderDeployment = var.forwarderName
}
}
resource "azurerm_eventhub" "ehub" {
name = local.eventHubName
namespace_name = azurerm_eventhub_namespace.ehubns.name
resource_group_name = azurerm_resource_group.rg.name
partition_count = 2
message_retention = 1
}
resource "azurerm_eventhub_namespace_authorization_rule" "ehubnsauthrule" {
name = local.eventHubNamespaceAuthRule
namespace_name = azurerm_eventhub_namespace.ehubns.name
resource_group_name = azurerm_eventhub_namespace.ehubns.resource_group_name
listen = true
send = false
manage = false
}
# ######################################################################################
# dynatrace-azure-forwarder.json
# ######################################################################################
resource "azurerm_virtual_network" "vnet" {
count = var.deployActiveGateContainer ? 1 : 0
name = local.virtualNetworkName
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
address_space = ["172.0.0.0/22"]
tags = {
LogsForwarderDeployment = var.forwarderName
}
}
resource "azurerm_subnet" "function_subnet" {
count = var.deployActiveGateContainer ? 1 : 0
name = "functionapp"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet[0].name
address_prefixes = ["172.0.1.0/24"]
service_endpoints = ["Microsoft.Storage"]
delegation {
name = "app-service-delegation"
service_delegation {
name = "Microsoft.Web/serverFarms"
}
}
}
resource "azurerm_subnet" "container_subnet" {
count = var.deployActiveGateContainer ? 1 : 0
name = "aci"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet[0].name
address_prefixes = ["172.0.0.0/24"]
delegation {
name = "private-subnet-delegation"
service_delegation {
name = "Microsoft.ContainerInstance/containerGroups"
}
}
}
resource "azurerm_network_profile" "network_profile" {
count = var.deployActiveGateContainer ? 1 : 0
name = local.networkProfileName
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
container_network_interface {
name = "eth0"
ip_configuration {
name = "ipconfigprofile1"
subnet_id = azurerm_subnet.container_subnet[0].id
}
}
tags = {
LogsForwarderDeployment = var.forwarderName
}
}
data "azurerm_subscription" "current" {
}
resource "azurerm_container_group" "container_group" {
count = var.deployActiveGateContainer ? 1 : 0
name = var.forwarderName
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
sku = "Standard"
subnet_ids = [azurerm_subnet.container_subnet[0].id]
container {
name = var.forwarderName
image = local.image
cpu = 1
memory = 1
ports {
port = 9999
protocol = "TCP"
}
environment_variables = {
DT_CAPABILITIES = "log_analytics_collector"
DT_ID_SKIP_HOSTNAME = "true"
DT_ID_SEED_SUBSCRIPTIONID = data.azurerm_subscription.current.id
DT_ID_SEED_RESOURCEGROUP = azurerm_resource_group.rg.name
DT_ID_SEED_RESOURCENAME = var.forwarderName
}
}
image_registry_credential {
server = local.dtHost
username = local.registryUser
password = var.targetPaasToken
}
restart_policy = "Always"
os_type = "Linux"
tags = {
LogsForwarderDeployment = var.forwarderName
}
}
resource "azurerm_storage_account" "storage_account" {
name = local.storageAccountName
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
account_tier = "Standard"
account_replication_type = "LRS"
network_rules {
default_action = "Allow"
bypass = ["AzureServices"]
virtual_network_subnet_ids = var.deployActiveGateContainer ? [azurerm_subnet.function_subnet[0].id] : []
}
min_tls_version = "TLS1_2"
enable_https_traffic_only = true
queue_encryption_key_type = "Account"
table_encryption_key_type = "Account"
tags = {
LogsForwarderDeployment = var.forwarderName
}
}
resource "azurerm_storage_container" "eventhub_container" {
name = "azure-webjobs-eventhub"
storage_account_name = azurerm_storage_account.storage_account.name
container_access_type = "private"
}
resource "azurerm_storage_container" "hosts_container" {
name = "azure-webjobs-hosts"
storage_account_name = azurerm_storage_account.storage_account.name
container_access_type = "private"
}
resource "azurerm_storage_container" "secrets_container" {
name = "azure-webjobs-secrets"
storage_account_name = azurerm_storage_account.storage_account.name
container_access_type = "private"
}
resource "azurerm_service_plan" "app_service_plan" {
name = local.appServicePlan
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
os_type = "Linux"
sku_name = "S1"
}
resource "azurerm_linux_function_app" "function_app" {
name = local.functionName
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
storage_account_name = azurerm_storage_account.storage_account.name
service_plan_id = azurerm_service_plan.app_service_plan.id
zip_deploy_file = "dynatrace-azure-log-forwarder.zip"
app_settings = {
FUNCTIONS_WORKER_RUNTIME = "python"
FUNCTIONS_EXTENSION_VERSION = "~4"
DYNATRACE_URL = var.deployActiveGateContainer ? "https://172.0.0.4:9999/e/${local.registryUser}" : var.targetUrl
DYNATRACE_ACCESS_KEY = var.targetAPIToken
EVENTHUB_CONNECTION_STRING = azurerm_eventhub_namespace_authorization_rule.ehubnsauthrule.primary_connection_string
EVENTHUB_NAME = local.eventHubName
AzureWebJobsStorage = azurerm_storage_account.storage_account.primary_connection_string
REQUIRE_VALID_CERTIFICATE = var.requireValidCertificate
SELF_MONITORING_ENABLED = var.selfMonitoringEnabled
RESOURCE_ID = local.functionName
REGION = azurerm_resource_group.rg.location
SCM_DO_BUILD_DURING_DEPLOYMENT = true
FILTER_CONFIG = var.filterConfig
EVENTHUB_CONNECTION_STRING__clientId = var.eventhubConnectionClientId
EVENTHUB_CONNECTION_STRING__credential = var.eventhubConnectionCredentials
EVENTHUB_CONNECTION_STRING__fullyQualifiedNamespace = var.eventhubConnectionFullyQualifiedNamespace
}
site_config {
always_on = true
application_stack {
python_version = "3.8"
}
}
}