The aws:amp/resourcePolicy:ResourcePolicy resource, part of the Pulumi AWS provider, attaches resource-based policies to Amazon Managed Service for Prometheus workspaces, controlling which AWS accounts and services can write or query metrics. This guide focuses on three capabilities: same-account access, cross-account sharing, and service principal permissions.
Resource policies reference existing AMP workspaces and use IAM policy documents to define permissions. The examples are intentionally small. Combine them with your own workspace configuration and KMS key grants if using customer-managed encryption.
Grant workspace access to your own account
Most deployments start by granting their own AWS account permissions to write and query metrics, establishing baseline access before adding external principals.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const exampleWorkspace = new aws.amp.Workspace("example", {alias: "example-workspace"});
const current = aws.getCallerIdentity({});
const example = pulumi.all([current, exampleWorkspace.arn]).apply(([current, arn]) => aws.iam.getPolicyDocumentOutput({
statements: [{
effect: "Allow",
principals: [{
type: "AWS",
identifiers: [current.accountId],
}],
actions: [
"aps:RemoteWrite",
"aps:QueryMetrics",
"aps:GetSeries",
"aps:GetLabels",
"aps:GetMetricMetadata",
],
resources: [arn],
}],
}));
const exampleResourcePolicy = new aws.amp.ResourcePolicy("example", {
workspaceId: exampleWorkspace.id,
policyDocument: example.apply(example => example.json),
});
import pulumi
import pulumi_aws as aws
example_workspace = aws.amp.Workspace("example", alias="example-workspace")
current = aws.get_caller_identity()
example = example_workspace.arn.apply(lambda arn: aws.iam.get_policy_document(statements=[{
"effect": "Allow",
"principals": [{
"type": "AWS",
"identifiers": [current.account_id],
}],
"actions": [
"aps:RemoteWrite",
"aps:QueryMetrics",
"aps:GetSeries",
"aps:GetLabels",
"aps:GetMetricMetadata",
],
"resources": [arn],
}]))
example_resource_policy = aws.amp.ResourcePolicy("example",
workspace_id=example_workspace.id,
policy_document=example.json)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/amp"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
exampleWorkspace, err := amp.NewWorkspace(ctx, "example", &.WorkspaceArgs{
Alias: pulumi.String("example-workspace"),
})
if err != nil {
return err
}
current, err := aws.GetCallerIdentity(ctx, &aws.GetCallerIdentityArgs{
}, nil);
if err != nil {
return err
}
example := exampleWorkspace.Arn.ApplyT(func(arn string) (iam.GetPolicyDocumentResult, error) {
return iam.GetPolicyDocumentResult(interface{}(iam.GetPolicyDocument(ctx, &iam.GetPolicyDocumentArgs{
Statements: []iam.GetPolicyDocumentStatement([]iam.GetPolicyDocumentStatement{
{
Effect: pulumi.StringRef(pulumi.String(pulumi.StringRef("Allow"))),
Principals: []iam.GetPolicyDocumentStatementPrincipal{
{
Type: "AWS",
Identifiers: interface{}{
current.AccountId,
},
},
},
Actions: []string{
"aps:RemoteWrite",
"aps:QueryMetrics",
"aps:GetSeries",
"aps:GetLabels",
"aps:GetMetricMetadata",
},
Resources: []string{
arn,
},
},
}),
}, nil))), nil
}).(iam.GetPolicyDocumentResultOutput)
_, err = amp.NewResourcePolicy(ctx, "example", &.ResourcePolicyArgs{
WorkspaceId: exampleWorkspace.ID(),
PolicyDocument: pulumi.String(example.ApplyT(func(example iam.GetPolicyDocumentResult) (*string, error) {
return &example.Json, nil
}).(pulumi.StringPtrOutput)),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var exampleWorkspace = new Aws.Amp.Workspace("example", new()
{
Alias = "example-workspace",
});
var current = Aws.GetCallerIdentity.Invoke();
var example = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementArgs
{
Effect = "Allow",
Principals = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementPrincipalArgs
{
Type = "AWS",
Identifiers = new[]
{
current.Apply(getCallerIdentityResult => getCallerIdentityResult.AccountId),
},
},
},
Actions = new[]
{
"aps:RemoteWrite",
"aps:QueryMetrics",
"aps:GetSeries",
"aps:GetLabels",
"aps:GetMetricMetadata",
},
Resources = new[]
{
exampleWorkspace.Arn,
},
},
},
});
var exampleResourcePolicy = new Aws.Amp.ResourcePolicy("example", new()
{
WorkspaceId = exampleWorkspace.Id,
PolicyDocument = example.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.amp.Workspace;
import com.pulumi.aws.amp.WorkspaceArgs;
import com.pulumi.aws.AwsFunctions;
import com.pulumi.aws.inputs.GetCallerIdentityArgs;
import com.pulumi.aws.iam.IamFunctions;
import com.pulumi.aws.iam.inputs.GetPolicyDocumentArgs;
import com.pulumi.aws.amp.ResourcePolicy;
import com.pulumi.aws.amp.ResourcePolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var exampleWorkspace = new Workspace("exampleWorkspace", WorkspaceArgs.builder()
.alias("example-workspace")
.build());
final var current = AwsFunctions.getCallerIdentity(GetCallerIdentityArgs.builder()
.build());
final var example = exampleWorkspace.arn().applyValue(_arn -> IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.effect("Allow")
.principals(GetPolicyDocumentStatementPrincipalArgs.builder()
.type("AWS")
.identifiers(current.accountId())
.build())
.actions(
"aps:RemoteWrite",
"aps:QueryMetrics",
"aps:GetSeries",
"aps:GetLabels",
"aps:GetMetricMetadata")
.resources(_arn)
.build())
.build()));
var exampleResourcePolicy = new ResourcePolicy("exampleResourcePolicy", ResourcePolicyArgs.builder()
.workspaceId(exampleWorkspace.id())
.policyDocument(example.json())
.build());
}
}
resources:
exampleWorkspace:
type: aws:amp:Workspace
name: example
properties:
alias: example-workspace
exampleResourcePolicy:
type: aws:amp:ResourcePolicy
name: example
properties:
workspaceId: ${exampleWorkspace.id}
policyDocument: ${example.json}
variables:
current:
fn::invoke:
function: aws:getCallerIdentity
arguments: {}
example:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- effect: Allow
principals:
- type: AWS
identifiers:
- ${current.accountId}
actions:
- aps:RemoteWrite
- aps:QueryMetrics
- aps:GetSeries
- aps:GetLabels
- aps:GetMetricMetadata
resources:
- ${exampleWorkspace.arn}
The policyDocument property contains an IAM policy that defines who can access the workspace and what actions they can perform. The principals block specifies the AWS account ID, while actions lists AMP-specific operations like RemoteWrite for ingestion and QueryMetrics for querying. The resources array must match the workspace ARN that the policy attaches to via workspaceId.
Share workspace access with another AWS account
Organizations with multiple AWS accounts often centralize metrics collection while allowing other accounts to write and query data.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.amp.Workspace("example", {alias: "example-workspace"});
const crossAccount = aws.iam.getPolicyDocumentOutput({
statements: [{
effect: "Allow",
principals: [{
type: "AWS",
identifiers: ["arn:aws:iam::123456789012:root"],
}],
actions: [
"aps:RemoteWrite",
"aps:QueryMetrics",
],
resources: [example.arn],
}],
});
const crossAccountResourcePolicy = new aws.amp.ResourcePolicy("cross_account", {
workspaceId: example.id,
policyDocument: crossAccount.apply(crossAccount => crossAccount.json),
});
import pulumi
import pulumi_aws as aws
example = aws.amp.Workspace("example", alias="example-workspace")
cross_account = aws.iam.get_policy_document_output(statements=[{
"effect": "Allow",
"principals": [{
"type": "AWS",
"identifiers": ["arn:aws:iam::123456789012:root"],
}],
"actions": [
"aps:RemoteWrite",
"aps:QueryMetrics",
],
"resources": [example.arn],
}])
cross_account_resource_policy = aws.amp.ResourcePolicy("cross_account",
workspace_id=example.id,
policy_document=cross_account.json)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/amp"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := amp.NewWorkspace(ctx, "example", &.WorkspaceArgs{
Alias: pulumi.String("example-workspace"),
})
if err != nil {
return err
}
crossAccount := iam.GetPolicyDocumentOutput(ctx, iam.GetPolicyDocumentOutputArgs{
Statements: iam.GetPolicyDocumentStatementArray{
&iam.GetPolicyDocumentStatementArgs{
Effect: pulumi.String("Allow"),
Principals: iam.GetPolicyDocumentStatementPrincipalArray{
&iam.GetPolicyDocumentStatementPrincipalArgs{
Type: pulumi.String("AWS"),
Identifiers: pulumi.StringArray{
pulumi.String("arn:aws:iam::123456789012:root"),
},
},
},
Actions: pulumi.StringArray{
pulumi.String("aps:RemoteWrite"),
pulumi.String("aps:QueryMetrics"),
},
Resources: pulumi.StringArray{
example.Arn,
},
},
},
}, nil)
_, err = amp.NewResourcePolicy(ctx, "cross_account", &.ResourcePolicyArgs{
WorkspaceId: example.ID(),
PolicyDocument: pulumi.String(crossAccount.ApplyT(func(crossAccount iam.GetPolicyDocumentResult) (*string, error) {
return &crossAccount.Json, nil
}).(pulumi.StringPtrOutput)),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Amp.Workspace("example", new()
{
Alias = "example-workspace",
});
var crossAccount = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementInputArgs
{
Effect = "Allow",
Principals = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementPrincipalInputArgs
{
Type = "AWS",
Identifiers = new[]
{
"arn:aws:iam::123456789012:root",
},
},
},
Actions = new[]
{
"aps:RemoteWrite",
"aps:QueryMetrics",
},
Resources = new[]
{
example.Arn,
},
},
},
});
var crossAccountResourcePolicy = new Aws.Amp.ResourcePolicy("cross_account", new()
{
WorkspaceId = example.Id,
PolicyDocument = crossAccount.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.amp.Workspace;
import com.pulumi.aws.amp.WorkspaceArgs;
import com.pulumi.aws.iam.IamFunctions;
import com.pulumi.aws.iam.inputs.GetPolicyDocumentArgs;
import com.pulumi.aws.amp.ResourcePolicy;
import com.pulumi.aws.amp.ResourcePolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Workspace("example", WorkspaceArgs.builder()
.alias("example-workspace")
.build());
final var crossAccount = IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.effect("Allow")
.principals(GetPolicyDocumentStatementPrincipalArgs.builder()
.type("AWS")
.identifiers("arn:aws:iam::123456789012:root")
.build())
.actions(
"aps:RemoteWrite",
"aps:QueryMetrics")
.resources(example.arn())
.build())
.build());
var crossAccountResourcePolicy = new ResourcePolicy("crossAccountResourcePolicy", ResourcePolicyArgs.builder()
.workspaceId(example.id())
.policyDocument(crossAccount.applyValue(_crossAccount -> _crossAccount.json()))
.build());
}
}
resources:
example:
type: aws:amp:Workspace
properties:
alias: example-workspace
crossAccountResourcePolicy:
type: aws:amp:ResourcePolicy
name: cross_account
properties:
workspaceId: ${example.id}
policyDocument: ${crossAccount.json}
variables:
crossAccount:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- effect: Allow
principals:
- type: AWS
identifiers:
- arn:aws:iam::123456789012:root
actions:
- aps:RemoteWrite
- aps:QueryMetrics
resources:
- ${example.arn}
Cross-account access uses an IAM principal ARN that identifies the target account’s root user. The example grants RemoteWrite and QueryMetrics permissions, enabling the external account to both ingest and query metrics. If your workspace uses customer-managed KMS keys for encryption, you must also grant the external account access to those keys through KMS grants.
Allow AWS services to query workspace metrics
Visualization tools like Amazon Managed Grafana need read-only access to query metrics without write permissions.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.amp.Workspace("example", {alias: "example-workspace"});
const serviceAccess = aws.iam.getPolicyDocumentOutput({
statements: [{
effect: "Allow",
principals: [{
type: "Service",
identifiers: ["grafana.amazonaws.com"],
}],
actions: [
"aps:QueryMetrics",
"aps:GetSeries",
"aps:GetLabels",
"aps:GetMetricMetadata",
],
resources: [example.arn],
}],
});
const serviceAccessResourcePolicy = new aws.amp.ResourcePolicy("service_access", {
workspaceId: example.id,
policyDocument: serviceAccess.apply(serviceAccess => serviceAccess.json),
});
import pulumi
import pulumi_aws as aws
example = aws.amp.Workspace("example", alias="example-workspace")
service_access = aws.iam.get_policy_document_output(statements=[{
"effect": "Allow",
"principals": [{
"type": "Service",
"identifiers": ["grafana.amazonaws.com"],
}],
"actions": [
"aps:QueryMetrics",
"aps:GetSeries",
"aps:GetLabels",
"aps:GetMetricMetadata",
],
"resources": [example.arn],
}])
service_access_resource_policy = aws.amp.ResourcePolicy("service_access",
workspace_id=example.id,
policy_document=service_access.json)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/amp"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := amp.NewWorkspace(ctx, "example", &.WorkspaceArgs{
Alias: pulumi.String("example-workspace"),
})
if err != nil {
return err
}
serviceAccess := iam.GetPolicyDocumentOutput(ctx, iam.GetPolicyDocumentOutputArgs{
Statements: iam.GetPolicyDocumentStatementArray{
&iam.GetPolicyDocumentStatementArgs{
Effect: pulumi.String("Allow"),
Principals: iam.GetPolicyDocumentStatementPrincipalArray{
&iam.GetPolicyDocumentStatementPrincipalArgs{
Type: pulumi.String("Service"),
Identifiers: pulumi.StringArray{
pulumi.String("grafana.amazonaws.com"),
},
},
},
Actions: pulumi.StringArray{
pulumi.String("aps:QueryMetrics"),
pulumi.String("aps:GetSeries"),
pulumi.String("aps:GetLabels"),
pulumi.String("aps:GetMetricMetadata"),
},
Resources: pulumi.StringArray{
example.Arn,
},
},
},
}, nil)
_, err = amp.NewResourcePolicy(ctx, "service_access", &.ResourcePolicyArgs{
WorkspaceId: example.ID(),
PolicyDocument: pulumi.String(serviceAccess.ApplyT(func(serviceAccess iam.GetPolicyDocumentResult) (*string, error) {
return &serviceAccess.Json, nil
}).(pulumi.StringPtrOutput)),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Amp.Workspace("example", new()
{
Alias = "example-workspace",
});
var serviceAccess = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementInputArgs
{
Effect = "Allow",
Principals = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementPrincipalInputArgs
{
Type = "Service",
Identifiers = new[]
{
"grafana.amazonaws.com",
},
},
},
Actions = new[]
{
"aps:QueryMetrics",
"aps:GetSeries",
"aps:GetLabels",
"aps:GetMetricMetadata",
},
Resources = new[]
{
example.Arn,
},
},
},
});
var serviceAccessResourcePolicy = new Aws.Amp.ResourcePolicy("service_access", new()
{
WorkspaceId = example.Id,
PolicyDocument = serviceAccess.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.amp.Workspace;
import com.pulumi.aws.amp.WorkspaceArgs;
import com.pulumi.aws.iam.IamFunctions;
import com.pulumi.aws.iam.inputs.GetPolicyDocumentArgs;
import com.pulumi.aws.amp.ResourcePolicy;
import com.pulumi.aws.amp.ResourcePolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Workspace("example", WorkspaceArgs.builder()
.alias("example-workspace")
.build());
final var serviceAccess = IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.effect("Allow")
.principals(GetPolicyDocumentStatementPrincipalArgs.builder()
.type("Service")
.identifiers("grafana.amazonaws.com")
.build())
.actions(
"aps:QueryMetrics",
"aps:GetSeries",
"aps:GetLabels",
"aps:GetMetricMetadata")
.resources(example.arn())
.build())
.build());
var serviceAccessResourcePolicy = new ResourcePolicy("serviceAccessResourcePolicy", ResourcePolicyArgs.builder()
.workspaceId(example.id())
.policyDocument(serviceAccess.applyValue(_serviceAccess -> _serviceAccess.json()))
.build());
}
}
resources:
example:
type: aws:amp:Workspace
properties:
alias: example-workspace
serviceAccessResourcePolicy:
type: aws:amp:ResourcePolicy
name: service_access
properties:
workspaceId: ${example.id}
policyDocument: ${serviceAccess.json}
variables:
serviceAccess:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- effect: Allow
principals:
- type: Service
identifiers:
- grafana.amazonaws.com
actions:
- aps:QueryMetrics
- aps:GetSeries
- aps:GetLabels
- aps:GetMetricMetadata
resources:
- ${example.arn}
Service principals use type: "Service" with the service’s domain name as the identifier. This example grants Grafana read-only actions (QueryMetrics, GetSeries, GetLabels, GetMetricMetadata) without RemoteWrite, preventing the service from modifying workspace data. Service principals don’t require account-specific identities.
Beyond these examples
These snippets focus on specific resource policy features: same-account and cross-account access, service principal permissions, and read and write action scoping. They’re intentionally minimal rather than full workspace access configurations.
The examples reference pre-existing infrastructure such as AMP workspaces and IAM permissions to create policy documents. They focus on attaching policies rather than provisioning the workspace itself.
To keep things focused, common policy patterns are omitted, including:
- Revision tracking (revisionId for policy updates)
- KMS key grants for encrypted workspaces
- Condition-based access controls
- Multiple principal types in one policy
These omissions are intentional: the goal is to illustrate how each policy feature is wired, not provide drop-in access control modules. See the AMP ResourcePolicy resource reference for all available configuration options.
Let's configure AWS Managed Prometheus Resource Policies
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Common Issues & Limitations
resources field matches the workspace ARN.Policy Configuration & Permissions
You can grant five Prometheus-compatible actions:
aps:RemoteWrite- Write metrics to the workspaceaps:QueryMetrics- Query metrics from the workspaceaps:GetSeries- Retrieve time series dataaps:GetLabels- Retrieve label names and valuesaps:GetMetricMetadata- Retrieve metric metadata
type to AWS and use the account’s root ARN in identifiers (e.g., arn:aws:iam::123456789012:root), as shown in the Cross-Account Access example.type to Service and use the service identifier in identifiers (e.g., grafana.amazonaws.com), as shown in the Service-Specific Access example.Using a different cloud?
Explore monitoring guides for other cloud providers: