Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.anyshift.io/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Connect your AWS account to Annie to enable real-time infrastructure mapping, monitoring, and intelligent insights. Annie will ingest your AWS resources and relationships to build a comprehensive knowledge graph of your cloud environment.

What Annie reads

The Terraform below creates an IAM policy that grants what Annie needs for the resource graph (bucket inventory and per-bucket metadata only — no object reads, no data-plane access):
  • S3: bucket inventory and per-bucket metadata (location, default encryption, event notifications, access points, multi-region access points). No object content is read for the resource graph.
  • Compute, network, identity, monitoring, application, KMS, notifications, and other services: Describe* / List* / Get* only.
  • No write actions. No kms:Decrypt, no secretsmanager:GetSecretValue (only secretsmanager:GetResourcePolicy for resource policies, not secret material).
If you also want Annie to ingest Terraform state files stored in S3, an additional bucket-scoped grant is needed — see Optional: Terraform state ingestion below.

Setup Guide

  1. Go to the Anyshift integrations page
  2. Navigate to the AWS section
  3. Follow the setup instructions to connect your AWS account

Step 1: Create the IAM policy

Create a least-privilege managed policy that Annie will use. The same policy is reused by both Option 1 (Assume Role) and Option 2 (IAM User) below.
data "aws_iam_policy_document" "annie_readonly" {
  statement {
    sid    = "AllowS3Metadata"
    effect = "Allow"
    actions = [
      "s3:GetAccessPoint",
      "s3:GetAccessPointPolicy",
      "s3:GetBucketLocation",
      "s3:GetBucketNotification",
      "s3:GetEncryptionConfiguration",
      "s3:GetMultiRegionAccessPoint",
      "s3:GetMultiRegionAccessPointRoutes",
      "s3:ListAccessPoints",
      "s3:ListAllMyBuckets",
      "s3:ListBucket",
      "s3:ListMultiRegionAccessPoints",
    ]
    resources = ["*"]
  }

  statement {
    sid    = "AllowComputeResources"
    effect = "Allow"
    actions = [
      "ec2:Describe*",
      "ecs:Describe*",
      "ecs:List*",
      "eks:DescribeAddon",
      "eks:DescribeCluster",
      "eks:DescribeNodegroup",
      "eks:ListAddons",
      "eks:ListClusters",
      "eks:ListNodegroups",
      "ecr:DescribeRepositories",
      "ecr:GetRepositoryPolicy",
      "lambda:GetAlias",
      "lambda:GetEventSourceMapping",
      "lambda:GetFunction",
      "lambda:GetFunctionConfiguration",
      "lambda:GetFunctionUrlConfig",
      "lambda:List*",
      "autoscaling:DescribeAutoScalingGroups",
      "autoscaling:DescribePolicies",
      "application-autoscaling:DescribeScalableTargets",
      "application-autoscaling:DescribeScalingPolicies",
    ]
    resources = ["*"]
  }

  statement {
    sid    = "AllowStorageResources"
    effect = "Allow"
    actions = [
      "rds:Describe*",
      "rds:ListTagsForResource",
      "dynamodb:DescribeKinesisStreamingDestination",
      "dynamodb:DescribeTable",
      "dynamodb:GetResourcePolicy",
      "dynamodb:ListTables",
      "elasticache:DescribeCacheClusters",
      "elasticache:DescribeCacheParameterGroups",
      "elasticache:DescribeCacheSubnetGroups",
      "elasticache:DescribeReplicationGroups",
      "elasticache:DescribeServerlessCaches",
      "backup:DescribeBackupVault",
      "backup:DescribeRecoveryPoint",
      "backup:GetBackupPlan",
      "backup:GetBackupSelection",
      "backup:GetBackupVaultAccessPolicy",
      "backup:GetBackupVaultNotifications",
      "backup:List*",
    ]
    resources = ["*"]
  }

  statement {
    sid    = "AllowNetworkResources"
    effect = "Allow"
    actions = [
      "elasticloadbalancing:Describe*",
      "route53:GetHostedZone",
      "route53:GetQueryLoggingConfig",
      "route53:GetReusableDelegationSet",
      "route53:List*",
      "cloudfront:GetDistribution",
      "cloudfront:GetDistributionConfig",
      "cloudfront:ListDistributions",
      "cloudfront:ListFunctions",
      "cloudfront:ListTagsForResource",
    ]
    resources = ["*"]
  }

  statement {
    sid    = "AllowIdentityResources"
    effect = "Allow"
    actions = [
      "iam:Get*",
      "iam:List*",
    ]
    resources = ["*"]
  }

  statement {
    sid    = "AllowMonitoringResources"
    effect = "Allow"
    actions = [
      "cloudwatch:DescribeAlarms",
      "cloudwatch:GetMetricStatistics",
      "cloudwatch:ListMetrics",
      "logs:DescribeLogGroups",
      "events:List*",
    ]
    resources = ["*"]
  }

  statement {
    sid    = "AllowApplicationResources"
    effect = "Allow"
    actions = [
      "sns:GetTopicAttributes",
      "sns:ListSubscriptionsByTopic",
      "sns:ListTopics",
      "sqs:GetQueueAttributes",
      "sqs:GetQueueUrl",
      "sqs:ListDeadLetterSourceQueues",
      "sqs:ListQueues",
      "apigateway:GET",
      "elasticmapreduce:DescribeStudio",
      "elasticmapreduce:ListStudioSessionMappings",
      "elasticmapreduce:ListStudios",
      "kinesis:DescribeStreamSummary",
      "kinesis:GetResourcePolicy",
      "kinesis:ListStreams",
      "kinesis:ListTagsForStream",
      "states:DescribeStateMachine",
      "states:ListStateMachines",
      "states:ListTagsForResource",
    ]
    resources = ["*"]
  }

  statement {
    sid    = "AllowKMS"
    effect = "Allow"
    actions = [
      "kms:DescribeKey",
      "kms:GetKeyPolicy",
      "kms:GetKeyRotationStatus",
      "kms:ListAliases",
      "kms:ListKeyPolicies",
      "kms:ListKeys",
      "kms:ListResourceTags",
    ]
    resources = ["*"]
  }

  statement {
    sid    = "AllowNotifications"
    effect = "Allow"
    actions = [
      "codestar-notifications:DescribeNotificationRule",
      "codestar-notifications:ListNotificationRules",
      "notifications:ListEventRules",
      "notifications:ListNotificationConfigurations",
    ]
    resources = ["*"]
  }

  statement {
    sid    = "AllowAdditionalServices"
    effect = "Allow"
    actions = [
      "acm:DescribeCertificate",
      "acm:GetCertificate",
      "acm:ListCertificates",
      "acm:ListTagsForCertificate",
      "athena:GetDataCatalog",
      "athena:GetWorkGroup",
      "athena:ListDataCatalogs",
      "athena:ListDatabases",
      "athena:ListEngineVersions",
      "athena:ListWorkGroups",
      "codebuild:BatchGetProjects",
      "codebuild:ListProjects",
      "codebuild:ListSourceCredentials",
      "docdb-elastic:GetCluster",
      "docdb-elastic:ListClusters",
      "docdb-elastic:ListTagsForResource",
      "emr-serverless:GetApplication",
      "emr-serverless:ListApplications",
      "firehose:DescribeDeliveryStream",
      "firehose:ListDeliveryStreams",
      "firehose:ListTagsForDeliveryStream",
      "glue:GetConnection",
      "glue:GetCrawler",
      "glue:GetCrawlers",
      "glue:GetDatabases",
      "glue:GetJob",
      "glue:GetJobs",
      "glue:GetSecurityConfiguration",
      "glue:GetTable",
      "glue:GetTables",
      "memorydb:DescribeACLs",
      "memorydb:DescribeClusters",
      "memorydb:DescribeParameterGroups",
      "memorydb:DescribeSubnetGroups",
      "memorydb:DescribeUsers",
      "airflow:GetEnvironment",
      "airflow:ListEnvironments",
      "airflow:ListTagsForResource",
      "oam:GetSink",
      "oam:ListAttachedLinks",
      "oam:ListLinks",
      "oam:ListSinks",
      "ram:GetResourceShareAssociations",
      "ram:GetResourceShares",
      "ram:ListPrincipals",
      "ram:ListResources",
      "sagemaker:DescribeNotebookInstance",
      "sagemaker:DescribeNotebookInstanceLifecycleConfig",
      "sagemaker:ListNotebookInstanceLifecycleConfigs",
      "sagemaker:ListNotebookInstances",
      "secretsmanager:DescribeSecret",
      "secretsmanager:GetResourcePolicy",
      "secretsmanager:ListSecrets",
      "ses:DescribeConfigurationSet",
      "ses:GetIdentityNotificationAttributes",
      "ses:ListConfigurationSets",
      "ses:ListIdentities",
      "transfer:DescribeServer",
      "transfer:ListServers",
      "vpc-lattice:GetAccessLogSubscription",
      "vpc-lattice:GetResourcePolicy",
      "vpc-lattice:GetServiceNetworkVpcAssociation",
      "vpc-lattice:ListAccessLogSubscriptions",
      "vpc-lattice:ListServiceNetworkResourceAssociations",
      "vpc-lattice:ListServiceNetworkServiceAssociations",
      "vpc-lattice:ListServiceNetworkVpcAssociations",
      "vpc-lattice:ListServiceNetworks",
      "waf:GetWebACL",
      "waf:ListIPSets",
      "waf:ListRuleGroups",
      "waf:ListRules",
      "waf:ListWebACLs",
      "waf-regional:GetWebACL",
      "waf-regional:ListIPSets",
      "waf-regional:ListResourcesForWebACL",
      "waf-regional:ListRuleGroups",
      "waf-regional:ListRules",
      "waf-regional:ListWebACLs",
      "wafv2:GetWebACLForResource",
      "wafv2:List*",
    ]
    resources = ["*"]
  }
}

resource "aws_iam_policy" "annie_readonly" {
  name   = "annie-readonly"
  policy = data.aws_iam_policy_document.annie_readonly.json
}
If you want to restrict which S3 buckets Annie can introspect, see Option 3 below before applying.

Step 2: Grant Annie access

Create the IAM User

  1. Using Terraform (Highly Recommended)
resource "aws_iam_user" "annie_user" {
  name = "annie-readonly-user"
}

resource "aws_iam_access_key" "annie_access_key" {
  user = aws_iam_user.annie_user.name
}

resource "aws_iam_user_policy_attachment" "annie_readonly" {
  user       = aws_iam_user.annie_user.name
  policy_arn = aws_iam_policy.annie_readonly.arn
}
  1. Using AWS Console
  • Go to IAM → Users → Add User
  • Enable Programmatic Access
  • Attach the annie-readonly policy created in Step 1.
  • Save Access Key ID and Secret Access Key

Configure in Anyshift

  • Enter the Access Key ID and Secret Access Key you obtained from the IAM user creation step.
  • Provide a descriptive AWS Account Name label (e.g., "read_only_user_for_anyshift").
Use this variant if you want Annie to introspect only certain S3 buckets. Bucket enumeration (s3:ListAllMyBuckets, s3:GetBucketLocation) cannot be resource-scoped at the IAM level — every bucket name and region will still be visible. Per-bucket metadata (encryption, notifications) will only be read for the buckets you list.Keep the data "aws_iam_policy_document" "annie_readonly" block from Step 1 unchanged. Add the blocks below in the same Terraform configuration, and change the policy argument on aws_iam_policy.annie_readonly from data.aws_iam_policy_document.annie_readonly.json to data.aws_iam_policy_document.annie_readonly_bucket_scoped.json.
data "aws_iam_policy_document" "annie_s3_scoped_override" {
  statement {
    sid    = "AllowS3Metadata"
    effect = "Allow"
    actions = [
      "s3:ListAllMyBuckets",
      "s3:GetBucketLocation",
      "s3:ListBucket",
    ]
    resources = ["*"]
  }

  statement {
    sid    = "AllowS3IntrospectionScoped"
    effect = "Allow"
    actions = [
      "s3:GetEncryptionConfiguration",
      "s3:GetBucketNotification",
    ]
    resources = [
      "arn:aws:s3:::your-bucket-name-1",
      "arn:aws:s3:::your-bucket-name-2",
    ]
  }
}

data "aws_iam_policy_document" "annie_readonly_bucket_scoped" {
  source_policy_documents   = [data.aws_iam_policy_document.annie_readonly.json]
  override_policy_documents = [data.aws_iam_policy_document.annie_s3_scoped_override.json]
}
The override_policy_documents argument replaces the original AllowS3Metadata statement (matched by sid) and appends the new AllowS3IntrospectionScoped statement.Tradeoff: buckets not listed in AllowS3IntrospectionScoped will appear in the Annie graph as bare entries (name + region) without encryption or notification attributes. S3 access points and multi-region access points are not bucket-scopable in IAM and are not introspected in this variant.

Optional: Terraform state ingestion

If you store Terraform state in S3 and want Annie to ingest it (drift detection, IaC-to-live mapping), grant the same role/user s3:GetObject and s3:ListBucket on your tfstate bucket(s) in addition to the policy above. Scope tightly to the buckets that hold state — Annie will only read keys you tell it to ingest, and only those grants are needed.
data "aws_iam_policy_document" "annie_tfstate_read" {
  statement {
    sid     = "AllowTfstateBucketList"
    effect  = "Allow"
    actions = ["s3:ListBucket"]
    resources = [
      "arn:aws:s3:::your-tfstate-bucket",
    ]
  }

  statement {
    sid     = "AllowTfstateObjectRead"
    effect  = "Allow"
    actions = ["s3:GetObject"]
    resources = [
      "arn:aws:s3:::your-tfstate-bucket/*",
    ]
  }
}

resource "aws_iam_policy" "annie_tfstate_read" {
  name   = "annie-tfstate-read"
  policy = data.aws_iam_policy_document.annie_tfstate_read.json
}
Attach aws_iam_policy.annie_tfstate_read.arn to the same role (Option 1) or user (Option 2) using the same aws_iam_role_policy_attachment / aws_iam_user_policy_attachment pattern shown above. If your state is encrypted with a customer-managed KMS key, also grant kms:Decrypt on that key’s ARN.

Features Enabled

Resource Monitoring

Real-time visibility into your cloud infrastructure

Dependency Mapping

Understand your infrastructure dependencies

Try Annie Today

Start building your infrastructure knowledge graph and unlock intelligent infrastructure management.

Create Account

Create your Anyshift account

Request Demo

See Annie’s knowledge graph in action