Skip to main content
Gå til innhold

Querying AWS CloudWatch from Grafana

Grafana can query CloudWatch metrics and logs from your team's AWS account. This uses cross-account IAM role assumption — Grafana assumes a role you create in your account to access your CloudWatch data.

Prerequisites

Before you begin, you need administrator rights in your Grafana organization. This allows you to create and configure data sources.

Request Admin Access

Contact the Platon observability team to request administrator rights for your organization. A separate Entra ID group will be created for your organization's admins. Once you're added to this group, you'll have the Editor or Admin role in your Grafana organization.

Step 1: Create an IAM Role in Your AWS Account

Create an IAM role in your AWS account that Grafana can assume. The role needs two things:

  1. A trust policy allowing the Grafana service role to assume it
  2. Permissions for the AWS services you want to query

Trust Policy

The role must trust the Grafana service role in the mgmt1 account (225881135767). Use the following trust policy:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal": {
"AWS": "arn:aws:iam::225881135767:role/Grafana-assume-role-mgmt1"
}
}
]
}
Cross-Team Access Risk

The trust policy above only verifies that the request comes from the shared Grafana service role — it does not restrict which Grafana user assumes the role. Since role naming conventions are documented here and AWS account numbers are not secret, another team could configure a data source in Grafana pointing to your role if they know or guess your account number.

If the resources you expose (e.g. logs) contain sensitive data, add an ExternalId condition to your trust policy. See Protecting Sensitive Resources with ExternalId below.

Permissions

Attach a policy with the permissions Grafana needs. For CloudWatch logs and metrics, a minimal policy looks like this:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:DescribeLogGroups",
"logs:GetLogGroupFields",
"logs:StartQuery",
"logs:StopQuery",
"logs:GetQueryResults",
"logs:GetLogEvents",
"logs:FilterLogEvents"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"cloudwatch:DescribeAlarmsForMetric",
"cloudwatch:DescribeAlarmHistory",
"cloudwatch:DescribeAlarms",
"cloudwatch:ListMetrics",
"cloudwatch:GetMetricData",
"cloudwatch:GetInsightRuleReport"
],
"Resource": "*"
}
]
}
Principle of Least Privilege

The example above grants read access to all log groups and metrics in your account. Restrict the Resource field if you want to limit which log groups or namespaces Grafana can access.

Terraform Example

If you use Terraform, here's a complete example:

resource "aws_iam_role" "grafana" {
name = "GrafanaIAMRole"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = "sts:AssumeRole"
Principal = {
AWS = "arn:aws:iam::225881135767:role/Grafana-assume-role-mgmt1"
}
}
]
})
}

resource "aws_iam_role_policy" "grafana_cloudwatch" {
name = "GrafanaCloudWatchAccess"
role = aws_iam_role.grafana.id

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"logs:DescribeLogGroups",
"logs:GetLogGroupFields",
"logs:StartQuery",
"logs:StopQuery",
"logs:GetQueryResults",
"logs:GetLogEvents",
"logs:FilterLogEvents",
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"cloudwatch:DescribeAlarmsForMetric",
"cloudwatch:DescribeAlarmHistory",
"cloudwatch:DescribeAlarms",
"cloudwatch:ListMetrics",
"cloudwatch:GetMetricData",
"cloudwatch:GetInsightRuleReport",
]
Resource = "*"
}
]
})
}

Note the ARN of the role you created — you'll need it when configuring the data source in Grafana.

Step 2: Add a CloudWatch Data Source in Grafana

  1. Log in to Grafana and switch to your organization

  2. Go to ConnectionsData sourcesAdd data source

  3. Search for CloudWatch and select it

  4. Configure the data source:

    SettingValue
    Authentication ProviderAWS SDK Default
    Assume Role ARNThe ARN of the role you created (e.g. arn:aws:iam::<your-account-id>:role/GrafanaIAMRole)
    Default RegionThe AWS region where your resources are (e.g. eu-north-1)
  5. Click Save & test to verify the connection


If "Save & test" fails, double-check that:

  • The trust policy on your role references arn:aws:iam::225881135767:role/Grafana-assume-role-mgmt1 exactly
  • Your role has the necessary CloudWatch/Logs permissions
  • The region is correct

Protecting Sensitive Resources with ExternalId

By default, any Grafana organization admin who knows your AWS account number can set up a data source that assumes your role. If the resources you expose through this role contain sensitive data (e.g. application logs with personal information), you should add an ExternalId condition to your trust policy.

The ExternalId acts as a shared secret between your IAM role and the Grafana data source. Only someone who knows the ExternalId can successfully assume the role.

1. Add the Condition to Your Trust Policy

Generate a random UUID (e.g. with uuidgen) and add a Condition block to your trust policy:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal": {
"AWS": "arn:aws:iam::225881135767:role/Grafana-assume-role-mgmt1"
},
"Condition": {
"StringEquals": {
"sts:ExternalId": "your-random-uuid-here"
}
}
}
]
}

If you use Terraform, add the condition to the assume_role_policy:

resource "aws_iam_role" "grafana" {
name = "GrafanaIAMRole"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = "sts:AssumeRole"
Principal = {
AWS = "arn:aws:iam::225881135767:role/Grafana-assume-role-mgmt1"
}
Condition = {
StringEquals = {
"sts:ExternalId" = var.grafana_external_id
}
}
}
]
})
}

2. Configure the ExternalId in Grafana

When configuring your CloudWatch data source in Grafana, enter the same UUID in the External ID field:

SettingValue
Authentication ProviderAWS SDK Default
Assume Role ARNThe ARN of your role
External IDThe same UUID you used in the trust policy
Default RegionYour AWS region
Treat the ExternalId as a Secret

The ExternalId should be treated like a password. Do not commit it to version control or share it outside your team. If you use Terraform, store it in a variable and manage it through your secrets pipeline.

How It Works

The authentication chain is:

  1. Grafana runs as a Kubernetes pod with an EKS service account
  2. The service account is linked to the IAM role Grafana-assume-role-mgmt1 via IRSA (IAM Roles for Service Accounts)
  3. When you query a CloudWatch data source, Grafana uses its service role to call sts:AssumeRole on your team's role
  4. Your role returns temporary credentials scoped to your account
  5. Grafana uses those credentials to query CloudWatch in your account

Beyond CloudWatch

The same pattern works for any AWS service that Grafana supports as a data source. If you want Grafana to access other AWS services in your account (e.g. X-Ray, Athena, Timestream), add the relevant permissions to your IAM role and configure the appropriate data source in Grafana with the same Assume Role ARN.