apm-wo-analysis/terraform/grafana.tf

252 lines
6.2 KiB
Terraform
Raw Normal View History

data "aws_ssm_parameter" "al2023_arm" {
name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64"
}
data "aws_acm_certificate" "grafana" {
domain = var.grafana_domain
statuses = ["ISSUED"]
most_recent = true
}
resource "aws_security_group" "alb" {
name = "apm-wo-analysis-grafana-alb"
description = "apm-wo grafana ALB"
vpc_id = aws_vpc.grafana.id
dynamic "ingress" {
for_each = var.office_cidrs
content {
description = "HTTPS from office ${ingress.value}"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [ingress.value]
}
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "apm-wo-analysis-grafana-alb"
}
}
resource "aws_security_group" "instance" {
name = "apm-wo-analysis-grafana-instance"
description = "apm-wo grafana instance"
vpc_id = aws_vpc.grafana.id
ingress {
description = "Grafana HTTP from the ALB only"
from_port = 3000
to_port = 3000
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "apm-wo-analysis-grafana-instance"
}
}
data "aws_iam_policy_document" "grafana_assume" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
resource "aws_iam_role" "grafana" {
name = "apm-wo-analysis-grafana"
path = "/tf-managed/"
description = "Grafana instance role: Athena, Glue, S3, SSM"
assume_role_policy = data.aws_iam_policy_document.grafana_assume.json
permissions_boundary = aws_iam_policy.exec_boundary.arn
}
data "aws_iam_policy_document" "grafana" {
statement {
sid = "AthenaQuery"
effect = "Allow"
actions = [
"athena:StartQueryExecution",
"athena:StopQueryExecution",
"athena:GetQueryExecution",
"athena:GetQueryResults",
"athena:GetWorkGroup",
]
resources = [
"arn:aws:athena:${var.aws_region}:${local.account_id}:workgroup/${local.athena_workgroup}",
]
}
statement {
sid = "AthenaList"
effect = "Allow"
actions = ["athena:ListWorkGroups"]
resources = ["*"]
}
statement {
sid = "GlueReadOnly"
effect = "Allow"
actions = [
"glue:GetDatabase",
"glue:GetDatabases",
"glue:GetTable",
"glue:GetTables",
"glue:GetPartition",
"glue:GetPartitions",
]
resources = [
"arn:aws:glue:${var.aws_region}:${local.account_id}:catalog",
"arn:aws:glue:${var.aws_region}:${local.account_id}:database/${local.glue_database}",
"arn:aws:glue:${var.aws_region}:${local.account_id}:table/${local.glue_database}/*",
]
}
statement {
sid = "ReadAnalytics"
effect = "Allow"
actions = [
"s3:GetObject",
]
resources = [
"${aws_s3_bucket.exports.arn}/analytics/*",
"${aws_s3_bucket.exports.arn}/${local.grafana_config_prefix}/*",
]
}
statement {
sid = "AthenaResults"
effect = "Allow"
actions = [
"s3:GetObject",
"s3:PutObject",
"s3:AbortMultipartUpload",
]
resources = [
"${aws_s3_bucket.exports.arn}/athena-results/*",
]
}
statement {
sid = "ListExports"
effect = "Allow"
actions = ["s3:ListBucket", "s3:GetBucketLocation"]
resources = [aws_s3_bucket.exports.arn]
}
}
resource "aws_iam_role_policy" "grafana" {
name = "grafana-athena-s3"
role = aws_iam_role.grafana.id
policy = data.aws_iam_policy_document.grafana.json
}
resource "aws_iam_role_policy_attachment" "grafana_ssm" {
role = aws_iam_role.grafana.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
resource "aws_iam_instance_profile" "grafana" {
name = "apm-wo-analysis-grafana"
path = "/tf-managed/"
role = aws_iam_role.grafana.name
}
resource "aws_instance" "grafana" {
ami = data.aws_ssm_parameter.al2023_arm.value
instance_type = "t4g.small"
subnet_id = aws_subnet.private["${var.aws_region}a"].id
vpc_security_group_ids = [aws_security_group.instance.id]
iam_instance_profile = aws_iam_instance_profile.grafana.name
user_data = templatefile("${path.module}/templates/grafana_userdata.sh.tftpl", {
config_bucket = aws_s3_bucket.exports.bucket
config_prefix = local.grafana_config_prefix
plugin_version = var.athena_plugin_version
grafana_domain = var.grafana_domain
})
metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
}
root_block_device {
volume_type = "gp3"
volume_size = 20
encrypted = true
delete_on_termination = false
}
tags = {
Name = "apm-wo-analysis-grafana"
(local.grafana_backup_tag) = "true"
}
lifecycle {
ignore_changes = [ami, user_data]
}
}
resource "aws_lb" "grafana" {
name = "apm-wo-analysis-grafana"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = [for s in aws_subnet.public : s.id]
}
resource "aws_lb_target_group" "grafana" {
name = "apm-wo-analysis-grafana"
port = 3000
protocol = "HTTP"
vpc_id = aws_vpc.grafana.id
target_type = "instance"
health_check {
path = "/api/health"
matcher = "200"
healthy_threshold = 2
unhealthy_threshold = 3
}
}
resource "aws_lb_target_group_attachment" "grafana" {
target_group_arn = aws_lb_target_group.grafana.arn
target_id = aws_instance.grafana.id
port = 3000
}
resource "aws_lb_listener" "grafana_https" {
load_balancer_arn = aws_lb.grafana.arn
port = 443
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
certificate_arn = data.aws_acm_certificate.grafana.arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.grafana.arn
}
}