Skip to main content

AWS Non-Human Identity and Workload Identity Surface

Purpose

This document catalogs every AWS identity type and mechanism through which autonomous, non-human workloads authenticate, assume authority, and access resources. For each identity type it provides:

  1. What it is and how it authenticates.
  2. How it maps to SecurityV0's 9-type entity model (identity, workload, connection, credential, owner, role, permission, resource, execution_evidence).
  3. Concrete security risks and ownership decay scenarios.
  4. AWS APIs that expose the data for connector ingestion.

This is the reference catalog for building the AWS connector's identity graph.


SecurityV0 Entity Model Reference

For mapping clarity, here are the 9 entity types and their purpose in the authority graph:

Entity TypePurpose
identityAn authenticatable principal — human or non-human. The "who" in an execution path.
workloadAn automation artifact that executes autonomously — Lambda function, Step Functions state machine, ECS task, Bedrock agent, etc.
connectionA configured link between systems, carrying auth context — EventBridge connection, API destination, VPC endpoint.
credentialA stored secret or key used for authentication — access key, secret in Secrets Manager, SSM SecureString.
ownerA person or team accountable for a workload, identity, or resource.
roleA permission assignment object — an IAM managed policy, permission set, or role assignment that sits between identity and permission.
permissionA specific action-resource grant — s3:GetObject on arn:aws:s3:::prod-data/*.
resourceA destination being accessed — S3 bucket, DynamoDB table, RDS cluster, Secrets Manager secret.
execution_evidenceA temporal proof that an execution path was exercised — CloudTrail event, invocation log.

1. IAM Users — Programmatic Access Keys and Service Accounts

What It Is

An IAM User is a persistent identity within an AWS account. Each user can have up to two long-lived access key pairs (AccessKeyId + SecretAccessKey) for programmatic API access. Despite AWS best-practice guidance to use IAM Roles instead, IAM Users remain widespread as de-facto service accounts, especially in legacy environments and third-party integrations that cannot assume roles.

How It Authenticates

  • Access key pairs: The AccessKeyId and SecretAccessKey are used to sign every AWS API request via SigV4. These credentials are static — they do not expire unless manually rotated or deactivated.
  • Console password (less relevant for NHI): Some IAM Users created for humans also have console passwords. For NHI discovery, console access is a signal that the "service account" may actually be a shared human account.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
IAM User (when used as NHI)identitymachine_account
Access Key ID + Secretcredentialaws_access_key
IAM Managed Policy attached to userpermissioniam_policy
IAM Inline Policy on userpermissioniam_inline_policy
IAM Group (container for users + policies)identityiam_group
Group membershipRelationship: MEMBER_OF

Security Risks and Ownership Decay

  • Orphaned service accounts: Engineer creates an IAM User for a CI/CD pipeline or third-party tool, leaves the company. The access keys remain active. Nobody rotates them. The user has AdministratorAccess because it was "temporary." This is the most common AWS NHI ownership decay pattern.
  • Key sprawl: A single IAM User's access key is embedded in multiple systems — Jenkins, Terraform state, Lambda environment variables, developer laptops. Rotating the key breaks unknown dependencies.
  • Dormant keys with standing access: IAM User has access keys that have not been used in 180+ days but retain broad permissions. AWS IAM Credential Report exposes this directly.
  • Shared service accounts: Multiple teams share one IAM User. When something breaks, nobody knows which system made the call. CloudTrail shows the IAM User ARN but not the upstream application.

Realistic scenario: A DevOps engineer creates svc-terraform-deploy IAM User with PowerUserAccess plus iam:* for Terraform state management. The engineer leaves. The Terraform pipeline still runs nightly, creating and modifying IAM roles. The access keys are 400 days old. Nobody in the org knows the user exists or that it has IAM write access. SecurityV0 discovers this as: orphaned identity, stale credential, overprivileged authority path, active execution evidence.

Discovery APIs

APIData Returned
iam:ListUsersAll IAM users in the account
iam:GetUserUser details, creation date, last activity
iam:ListAccessKeysAccess key IDs and their status (Active/Inactive) per user
iam:GetAccessKeyLastUsedLast used date, region, and service for each access key
iam:ListUserPoliciesInline policy names on a user
iam:GetUserPolicyInline policy document
iam:ListAttachedUserPoliciesManaged policies attached to a user
iam:ListGroupsForUserGroup memberships
iam:ListMFADevicesMFA status (presence/absence is a risk signal for NHI)
iam:GenerateCredentialReport + iam:GetCredentialReportCSV report with all users, key ages, last used dates, MFA, password status

2. IAM Roles — The Primary AWS NHI Mechanism

What It Is

An IAM Role is an identity that has no long-lived credentials. Instead, it is assumed by another principal (user, service, or another role) via AWS STS. The role has two policy components:

  1. Trust policy (AssumeRolePolicyDocument): Defines WHO can assume this role — a list of principals (AWS accounts, services, federated identity providers).
  2. Permission policies (identity-based): Define WHAT the role can do once assumed — attached managed policies and inline policies.

Roles are the backbone of all modern AWS NHI patterns. Every service-specific identity pattern below is a specialized form of role assumption.

How It Authenticates

The assuming principal calls sts:AssumeRole (or sts:AssumeRoleWithWebIdentity for OIDC, or sts:AssumeRoleWithSAML for SAML). STS validates the request against the role's trust policy and returns temporary credentials (access key, secret key, session token) valid for 1-12 hours.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
IAM Roleidentityiam_role
Trust policyRelationship: TRUSTS (from role to the allowed principals)
Managed policy attachmentRelationship: HAS_ROLE (identity to role entity)
Inline policyroleiam_inline_policy
Managed policyroleiam_policy
Permission boundaryRelationship: CONSTRAINED_BY (ceiling on effective permissions)
AssumeRole session (STS)execution_evidencests_assume_role

Security Risks and Ownership Decay

  • Trust policy drift: A role's trust policy is broadened to add a new account or service principal, then never tightened back. Over time, principals that should not assume the role can.
  • Wildcard trust: Trust policies with "Principal": {"AWS": "*"} (any AWS account) or "Principal": "*" (any principal including anonymous) are critical misconfigurations. These make the role publicly assumable, constrained only by conditions (which may be absent).
  • Permission accumulation: Policies are attached to roles incrementally to fix bugs or enable new features. Nobody removes the old permissions. The role grows monotonically.
  • Role purpose decay: A role was created for a specific workload. That workload is decommissioned. The role remains, attached to a different workload that does not need the same permissions.

Discovery APIs

APIData Returned
iam:ListRolesAll roles in the account, including path, ARN, trust policy
iam:GetRoleRole detail including trust policy document
iam:ListRolePoliciesInline policies on a role
iam:GetRolePolicyInline policy document
iam:ListAttachedRolePoliciesManaged policies attached to a role
iam:GetPolicy + iam:GetPolicyVersionManaged policy document (the actual permission statements)
iam:ListRoleTagsTags — may contain owner, team, or purpose metadata
iam:GetServiceLastAccessedDetailsServices the role has accessed and when (Access Advisor)

2.1 EC2 Instance Profiles

What It Is

An instance profile is a container that wraps exactly one IAM Role and attaches it to an EC2 instance. Applications running on the instance retrieve temporary credentials from the Instance Metadata Service (IMDS) at http://169.254.169.254/latest/meta-data/iam/security-credentials/{role-name}.

How It Authenticates

The EC2 instance's hypervisor manages the credentials. The AWS SDK on the instance automatically retrieves and refreshes temporary credentials from IMDS. No access keys are stored on the instance. IMDSv2 (token-required) mitigates SSRF-based credential theft.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeNotes
EC2 Instanceworkload (subtype: ec2_instance)The running compute
Instance ProfileEdge annotation on RUNS_ASNot a separate entity — it is the binding mechanism
IAM Role (the one in the profile)identity (subtype: iam_role)The role the instance assumes

Security Risks

  • Overprivileged instance roles: EC2 instances often run multiple applications. The instance role must be broad enough for all of them. This violates least privilege.
  • SSRF to IMDS: If an application on the instance has an SSRF vulnerability and IMDSv1 is enabled (no hop limit, no token requirement), an attacker can steal the role's temporary credentials from the metadata endpoint.
  • Long-running instances with stale roles: EC2 instances run for months or years. The role's permissions grow, the owning team changes, but the instance keeps running.
  • Shared instance profiles: Multiple instances share the same instance profile/role. Compromise of one instance grants the attacker the same authority as all others.

Realistic scenario: A data engineering team launches an EC2 instance in 2024 for a batch ETL job. The instance profile role has s3:* on arn:aws:s3:::* and dynamodb:* on the production tables. The ETL job is migrated to Glue in 2025, but the EC2 instance keeps running because "something might still use it." IMDSv1 is enabled. The role has not been touched in 18 months. SecurityV0 discovers: workload with orphaned ownership, overprivileged identity, no recent execution evidence on the original ETL path but the instance is still running.

Discovery APIs

APIData Returned
iam:ListInstanceProfilesAll instance profiles and their associated roles
iam:GetInstanceProfileInstance profile detail with role ARN
ec2:DescribeInstancesRunning instances with IamInstanceProfile field
ec2:DescribeInstanceAttribute (disableApiTermination)Instance protection state
ec2:DescribeInstances (MetadataOptions)IMDSv1/v2 configuration

2.2 ECS Task Roles

What It Is

Amazon ECS has two distinct IAM roles per task definition:

  1. Task Role (taskRoleArn): The identity used by the application code inside the container. This is the workload's runtime identity — the authority surface SecurityV0 cares about most.
  2. Task Execution Role (executionRoleArn): The identity used by the ECS agent to pull container images from ECR, push logs to CloudWatch, and retrieve secrets for injection. This is infrastructure-level authority.

How It Authenticates

The ECS agent injects temporary credentials for the task role into the container via the credential endpoint (http://169.254.170.2/...). The container's AWS SDK automatically retrieves them. Each task gets isolated credentials — one task cannot access another task's role credentials.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
ECS Serviceworkloadecs_service
ECS Task Definitionworkloadecs_task
Task Roleidentity (subtype: iam_role)Runtime identity
Execution Roleidentity (subtype: iam_role)Infrastructure identity
Container Image (ECR)resourceecr_image

Relationships:

  • ECS Task → RUNS_AS → Task Role (runtime authority)
  • ECS Task → PULLS_VIA → Execution Role (infrastructure authority)
  • ECS Task → DEPLOYED_FROM → ECR Repository (supply chain lineage)

Security Risks

  • Task role vs execution role confusion: Teams use the execution role for application permissions because "it worked." This means the ECS agent and the application share a single, overprivileged role.
  • Missing task role: A task definition has no taskRoleArn — the application inherits the host's (EC2 launch type) or gets no role (Fargate). On EC2 launch type, this means the container gets the EC2 instance role, which may be broadly privileged.
  • Execution role with secret access: The execution role can be configured to retrieve secrets from Secrets Manager for injection into environment variables. If the execution role has broader secret access than needed, it can read secrets meant for other services.

Realistic scenario: An ECS service runs a payment processing application. The task definition was copied from a template that included both taskRoleArn and executionRoleArn pointing to the same role — ecsPaymentServiceRole. This role has permissions for ECR pull, CloudWatch Logs, Secrets Manager (for DB credentials), AND s3:* on the data lake bucket (because someone debugging added it temporarily). The application only needs the DB credentials and one S3 prefix. The task has been running for 14 months. The original developer left 9 months ago. SecurityV0 discovers: scope drift on the shared role, overprivileged authority path to the data lake, orphaned ownership.

Discovery APIs

APIData Returned
ecs:ListTaskDefinitionsAll task definition ARNs
ecs:DescribeTaskDefinitionTask role ARN, execution role ARN, container definitions, image URIs
ecs:ListServicesServices per cluster
ecs:DescribeServicesService details, task definition reference, desired count
ecs:ListClusters + ecs:DescribeClustersCluster metadata

2.3 EKS Pod Identity and IRSA

What It Is

Amazon EKS provides two mechanisms for pods to assume IAM roles:

IRSA (IAM Roles for Service Accounts) — the older mechanism:

  • Creates an OIDC identity provider in IAM for the EKS cluster.
  • The IAM role's trust policy trusts the cluster's OIDC provider with conditions on the Kubernetes service account name and namespace.
  • The pod's service account is annotated with the IAM role ARN.
  • The pod receives a projected JWT token that it exchanges for temporary AWS credentials via sts:AssumeRoleWithWebIdentity.

EKS Pod Identity — the newer mechanism (GA since late 2023):

  • Uses the EKS Pod Identity Agent (a DaemonSet) running on each node.
  • An explicit PodIdentityAssociation resource binds a Kubernetes service account to an IAM role.
  • The pod gets credentials from a local agent endpoint — no OIDC provider configuration required.
  • The trust policy trusts the pods.eks.amazonaws.com service principal.

How It Authenticates

  • IRSA: Pod → projected service account token (JWT signed by cluster OIDC provider) → sts:AssumeRoleWithWebIdentity → temporary AWS credentials.
  • Pod Identity: Pod → local agent endpoint → EKS Pod Identity Agent → sts:AssumeRoleForPodIdentity → temporary AWS credentials.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
EKS Clusterworkloadeks_cluster
Kubernetes Deployment/Podworkloadeks_workload
Kubernetes Service Accountidentityk8s_service_account
IAM Role (assumed by pod)identityiam_role
OIDC Provider (IRSA)connectionoidc_provider
PodIdentityAssociationRelationship: ASSUMES_VIA

Relationships:

  • EKS Workload → RUNS_AS → K8s Service Account → ASSUMES → IAM Role
  • K8s Service Account → TRUSTS_VIA → OIDC Provider (IRSA)
  • PodIdentityAssociation binds service account + namespace to role (Pod Identity)

Security Risks

  • Overly broad OIDC trust conditions: The IAM role's trust policy condition for IRSA uses StringLike instead of StringEquals, or uses a wildcard for the service account name. This allows any service account in any namespace to assume the role.
  • Namespace-scoped but not service-account-scoped: Trust policy condition checks system:serviceaccount:*:* in a namespace pattern but does not pin the specific service account name.
  • Stale pod identity associations: A PodIdentityAssociation remains after the workload is removed. The IAM role stays assumable by any pod using that service account name in that namespace.
  • Cross-namespace impersonation: If RBAC in the EKS cluster allows creating service accounts in the target namespace, an attacker can create a service account with the right annotation and assume the role.

Realistic scenario: A data science team sets up IRSA for a Spark workload in namespace analytics. The trust policy condition is StringLike: system:serviceaccount:analytics:*. Six months later, the team deploys a debugging pod in the same namespace with a different service account. Because the condition is a wildcard on the service account name, the debugging pod can assume the same IAM role that has s3:* on the data lake. SecurityV0 discovers: overly permissive trust condition, multiple workloads sharing the same authority path, the debugging pod was never meant to access the data lake.

Discovery APIs

APIData Returned
eks:ListClustersAll EKS clusters
eks:DescribeClusterCluster OIDC issuer URL, endpoint, version
eks:ListPodIdentityAssociationsPod identity bindings per cluster
eks:DescribePodIdentityAssociationService account name, namespace, role ARN
iam:ListOpenIDConnectProvidersOIDC providers (includes EKS cluster OIDC)
iam:GetOpenIDConnectProviderProvider URL, client IDs, thumbprints
IAM Role trust policy analysisRoles trusting the cluster's OIDC provider URL (parsed from GetRole)

2.4 Lambda Execution Roles

What It Is

Every Lambda function has exactly one execution role. This role is assumed by the Lambda service when the function is invoked. The role's permissions define what the function code can access — S3 buckets, DynamoDB tables, Secrets Manager secrets, other AWS services, and external APIs (if network egress is allowed).

How It Authenticates

The Lambda service calls sts:AssumeRole on behalf of the function. The function code receives temporary credentials via the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN environment variables. These are auto-refreshed by the Lambda runtime.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
Lambda Functionworkloadlambda_function
Execution Roleidentityiam_role
Event Source MappingRelationship: TRIGGERED_BY
Lambda Resource PolicyAuthority edge from invoker to function
Environment variable (SECRET_ARN, DB_URL)Inferred relationship to resource

Security Risks

  • Shared execution roles: Multiple Lambda functions share one execution role. The role must be broad enough for all functions. Each function gets more authority than it needs.
  • Execution role with admin access: During development, someone attaches AdministratorAccess to the Lambda role. It ships to production.
  • Orphaned functions: The business process the function served is decommissioned, but the function remains deployed and the CloudWatch Events rule still triggers it nightly.
  • Environment variable credential leakage: The function's environment variables contain hardcoded credentials (database passwords, API keys) rather than using Secrets Manager with fine-grained role permissions. Anyone with lambda:GetFunction or lambda:GetFunctionConfiguration can read them.

Realistic scenario: A Lambda function process-claims was created 2 years ago by a contractor. The execution role claims-processor-role has been modified 14 times since creation. It now has s3:*, dynamodb:*, secretsmanager:*, and sqs:* on Resource: *. The function runs daily via an EventBridge schedule. The contractor left 18 months ago. The function's code has not been updated in 11 months. SecurityV0 discovers: orphaned ownership (departed contractor), scope drift (14 policy modifications), overprivileged authority paths to every S3 bucket and DynamoDB table in the account, active execution evidence (daily invocations).

Discovery APIs

APIData Returned
lambda:ListFunctionsAll functions with execution role ARN, runtime, handler
lambda:GetFunctionFull function config including VPC, layers, environment vars (keys only for security)
lambda:GetFunctionConfigurationConfig detail including execution role ARN
lambda:GetPolicyResource-based policy (who can invoke)
lambda:ListEventSourceMappingsEvent source mappings (SQS, DynamoDB Streams, Kinesis triggers)
lambda:ListTagsTags on the function

2.5 Step Functions Execution Roles

What It Is

Every Step Functions state machine has an execution role that defines what actions the state machine can perform. Step Functions state machines are orchestrators — they invoke Lambda functions, start ECS tasks, call DynamoDB, send messages to SQS/SNS, make HTTP calls, and chain to other state machines.

How It Authenticates

The Step Functions service assumes the execution role via STS when the state machine execution starts. Each state in the machine uses these credentials to invoke its target service.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
Step Functions State Machineworkloadstep_function
Execution Roleidentityiam_role
Each state's target (Lambda, ECS, DynamoDB, HTTP)Relationship: INVOKES

Security Risks

  • Orchestrator privilege escalation: The state machine's execution role must have permissions for every service it orchestrates. A state machine that invokes 10 Lambda functions, writes to 3 DynamoDB tables, and sends messages to 2 SQS queues needs a role covering all of them. If one step is removed, the permission is rarely cleaned up.
  • HTTP task egress: Step Functions can call arbitrary HTTPS endpoints via HTTP Tasks. The execution role needs states:InvokeHTTPEndpoint and the state machine definition includes the external URL. This is an egress path that bypasses typical network controls.
  • Cross-account invocation: State machines can invoke resources in other accounts if the execution role has cross-account permissions. The state machine definition reveals the target ARN, but the cross-account trust is in the IAM role.

Discovery APIs

APIData Returned
states:ListStateMachinesAll state machines in the account
states:DescribeStateMachineDefinition (JSON), execution role ARN, type, logging config
states:ListExecutionsRecent executions with status and timestamps
states:ListTagsForResourceTags

2.6 Glue Job Roles

What It Is

AWS Glue jobs (ETL, Spark, Python shell) run under a specified IAM role. This role grants the job access to data sources (S3, JDBC, DynamoDB), data targets, and the Glue Data Catalog.

How It Authenticates

The Glue service assumes the specified role when the job runs. The job's code receives temporary credentials.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
Glue Jobworkloadglue_job
Glue Execution Roleidentityiam_role
Glue Data Catalogresourceglue_catalog
S3 source/targetresources3_bucket

Security Risks

  • Overprivileged Glue roles: Glue roles often get s3:* and glue:* because the job needs to read from and write to multiple locations. The AWS-managed policy AWSGlueServiceRole is broad.
  • JDBC credential exposure: Glue connections store JDBC passwords. The Glue role needs glue:GetConnection to retrieve them. If the role is shared across jobs, all jobs can read all connection passwords.
  • Dormant Glue jobs: ETL pipelines are created for one-time migrations, never decommissioned. The role retains access to production data sources.

Discovery APIs

APIData Returned
glue:GetJobsAll Glue jobs with role ARN, command, connections
glue:GetJobJob detail
glue:GetConnectionsConnections (JDBC, Kafka, etc.) with metadata
glue:GetCrawlersCrawlers with roles
glue:GetJobRunsRecent execution history

2.7 SageMaker Execution Roles

What It Is

SageMaker notebooks, training jobs, and endpoints run under IAM roles. A SageMaker execution role grants access to S3 training data, ECR images, model artifacts, and other AWS services.

How It Authenticates

The SageMaker service assumes the execution role. Notebook instances use the role via IMDS (similar to EC2). Training jobs and endpoints receive temporary credentials injected by the service.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
SageMaker Notebook Instanceworkloadsagemaker_notebook
SageMaker Training Jobworkloadsagemaker_training_job
SageMaker Endpointworkloadsagemaker_endpoint
Execution Roleidentityiam_role

Security Risks

  • Notebook instance with broad role: SageMaker notebooks are interactive compute environments. The execution role often has s3:* and sagemaker:* because data scientists need to experiment. This role persists after the notebook is shared or the scientist leaves.
  • Model endpoint with production data access: An inference endpoint's role has access to production databases or S3 buckets for real-time inference. The model may be outdated, but the endpoint and its role persist.
  • Training data exfiltration path: The training job role can read sensitive S3 data and write to an output bucket. If the output bucket has a permissive policy, the training data can be exfiltrated.

Discovery APIs

APIData Returned
sagemaker:ListNotebookInstancesNotebook instances with role ARN, status
sagemaker:DescribeNotebookInstanceFull config including role, network, lifecycle
sagemaker:ListTrainingJobsTraining jobs with role ARN
sagemaker:ListEndpointsInference endpoints
sagemaker:DescribeEndpointEndpoint config including model and role

2.8 CodeBuild / CodePipeline Service Roles

What It Is

  • CodeBuild projects have a service role that defines what the build environment can do — pull from CodeCommit/GitHub, push to ECR, deploy to Lambda/ECS, store artifacts in S3.
  • CodePipeline pipelines have a service role that orchestrates the pipeline stages — triggering CodeBuild, deploying to ECS, invoking Lambda functions.

How It Authenticates

Both services assume their specified IAM role via STS. CodeBuild containers receive credentials as environment variables. CodePipeline uses the role for all stage transitions.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
CodeBuild Projectworkloadcodebuild_project
CodePipeline Pipelineworkloadcodepipeline_pipeline
CodeBuild Service Roleidentityiam_role
CodePipeline Service Roleidentityiam_role
Artifact S3 Bucketresources3_bucket
ECR Repository (push target)resourceecr_repository

Security Risks

  • CI/CD to production authority chain: A CodeBuild role that can push to ECR and update ECS services has transitive authority over production workloads. A compromised build (e.g., via dependency injection) becomes a production compromise.
  • Source credential exposure: CodeBuild projects may have environment variables with GitHub tokens or other source credentials. These are visible to anyone with codebuild:BatchGetProjects.
  • Pipeline role drift: CodePipeline's service role accumulates permissions as new stages are added. Old stage permissions are never removed.

Discovery APIs

APIData Returned
codebuild:ListProjects + codebuild:BatchGetProjectsProjects with service role, environment, source config
codepipeline:ListPipelines + codepipeline:GetPipelinePipeline stages, actions, service role
codebuild:ListBuildsForProjectRecent build history

2.9 EMR Roles

What It Is

Amazon EMR clusters use multiple IAM roles:

  1. EMR Service Role (EMR_DefaultRole): Used by the EMR service to provision EC2 instances and manage the cluster.
  2. EC2 Instance Profile Role (EMR_EC2_DefaultRole): Used by the EC2 instances in the cluster — this is the runtime identity for Spark/Hadoop jobs.
  3. EMR Notebooks Execution Role: Used by EMR notebooks for interactive analysis.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
EMR Clusterworkloademr_cluster
EC2 Instance Profile Roleidentityiam_role
Service Roleidentityiam_role (infrastructure)

Security Risks

  • Default roles with broad permissions: The AWS-managed default EMR roles (EMR_DefaultRole, EMR_EC2_DefaultRole) have broad permissions. Many customers use these defaults without customization.
  • Long-running clusters with stale roles: EMR clusters for data processing may run for months. The instance profile role retains all permissions, even after the processing need changes.
  • EMRFS encryption key access: EMR clusters accessing encrypted S3 data need KMS permissions. The instance profile role's KMS grants may extend beyond the specific keys needed.

Discovery APIs

APIData Returned
emr:ListClustersAll clusters with state
emr:DescribeClusterService role, instance profile, security config
emr:ListStepsJob steps and execution history

2.10 Redshift Service Roles

What It Is

Amazon Redshift clusters can be associated with one or more IAM roles. These roles are used for:

  • COPY and UNLOAD commands (reading from/writing to S3)
  • Redshift Spectrum (querying S3 data via Glue Catalog)
  • Cross-service access (Lambda UDFs, Kinesis ingestion)

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
Redshift Clusterworkloadredshift_cluster
Associated IAM Role(s)identityiam_role
Default IAM Role (for the cluster)Relationship: RUNS_AS (default authority)

Security Risks

  • Multiple roles on a cluster: Redshift allows associating multiple roles. Any query can use iam_role parameter to select which role to assume. This means the effective authority of the cluster is the UNION of all associated roles.
  • COPY command data exfiltration: A role with s3:GetObject on broad prefixes allows any Redshift user with COPY access to read arbitrary S3 data.
  • Cross-account S3 access: Redshift roles frequently have cross-account S3 access for data sharing. The cross-account trust is in the role, not visible from the Redshift console.

Discovery APIs

APIData Returned
redshift:DescribeClustersCluster details including associated IAM role ARNs
redshift:DescribeLoggingStatusAudit logging configuration

3. Service-Linked Roles

What It Is

Service-linked roles (SLRs) are IAM roles created automatically by AWS services. They have a predefined trust policy (trusting only that service) and a predefined set of permissions. They cannot be modified by the customer — only deleted (and only if the service is not in use).

Examples:

  • AWSServiceRoleForElasticLoadBalancing — created by ELB
  • AWSServiceRoleForAmazonEKS — created by EKS
  • AWSServiceRoleForSecurityHub — created by Security Hub
  • AWSServiceRoleForConfig — created by AWS Config

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
Service-Linked Roleidentityservice_linked_role

These are low-priority for NHI risk assessment because they are AWS-managed and cannot be modified. However, they should be visible in the graph for completeness — they are real IAM identities with real permissions that can appear in CloudTrail.

Security Risks

  • Low direct risk: SLRs are tightly scoped by AWS. The primary risk signal is their existence — an SLR indicates a service is enabled in the account, which informs the attack surface.
  • Indirect dependency risk: A service-linked role for a service (e.g., RDS) may have permissions that are broader than expected. Since customers cannot modify the policy, they may not realize what the SLR can do.
  • Inventory signal: The set of SLRs in an account tells you which services are active. This is useful for attack surface mapping.

Discovery APIs

APIData Returned
iam:ListRoles (filter by path /aws-service-role/)All service-linked roles
iam:GetRoleTrust policy, description, max session duration
iam:ListAttachedRolePoliciesAWS-managed policy attached to the SLR

4. Cross-Account Assume-Role Chains

What It Is

Cross-account role assumption is the mechanism by which a principal in Account A assumes a role in Account B. This is the primary mechanism for:

  • Multi-account workload architectures
  • Shared services access
  • Third-party vendor access
  • Management/audit account access

Role chaining occurs when the assumed role in Account B then assumes a role in Account C. AWS allows role chaining up to the session duration limits, but chained sessions have a maximum duration of 1 hour.

How It Authenticates

  1. Principal in Account A calls sts:AssumeRole with the role ARN in Account B.
  2. The role in Account B's trust policy must allow Account A's principal.
  3. STS returns temporary credentials scoped to the role in Account B.
  4. The role in Account B can then call sts:AssumeRole for a role in Account C (chaining).

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity Type
Cross-account trust relationshipRelationship: TRUSTS from target role to source principal
AssumeRole hopIncrements auth_chain_depth on the access path
ExternalId conditionProperty on the TRUSTS relationship
Role chain (A→B→C)Multiple ASSUMES edges in sequence

Security Risks — The Confused Deputy Problem

The confused deputy attack occurs when a service (Account B) is tricked into using its cross-account access on behalf of an unauthorized principal. The classic prevention is the ExternalId condition in the trust policy. Without ExternalId:

  1. Customer A tells Vendor to assume role arn:aws:iam::111111111111:role/VendorRole.
  2. Vendor assumes the role and does its work.
  3. Malicious Customer B tells Vendor to assume arn:aws:iam::111111111111:role/VendorRole (Customer A's role ARN).
  4. If the trust policy only checks "Principal": {"AWS": "arn:aws:iam::VENDOR:root"}, the Vendor can assume Customer A's role on behalf of Malicious Customer B.

The fix: "Condition": {"StringEquals": {"sts:ExternalId": "customer-specific-secret"}}.

Cross-account trust amplification: A role in a dev/sandbox account trusts a role in the production account. If the dev account is compromised (weaker controls), the attacker can assume the prod role and access production data.

Stale cross-account trusts: A vendor relationship ends. The trust policy in the customer's account still allows the vendor to assume the role. The vendor retains access indefinitely.

Realistic scenario: Company sets up a cross-account role for a SaaS monitoring vendor in 2023. The vendor contract ends in 2024. Nobody removes the trust policy. The vendor's AWS account (VENDOR_ACCOUNT_ID) is still listed in the trust policy of a role with ReadOnlyAccess to the production account. The vendor (or anyone who compromises the vendor account) can still assume the role and read all production data. SecurityV0 discovers: cross-account trust to external account, no recent execution evidence (the vendor stopped using it), no owner assigned to the trust relationship.

Discovery APIs

Cross-account trusts are discovered by parsing trust policies:

APIData Returned
iam:ListRoles + iam:GetRoleTrust policy documents — parse Principal field for external account IDs
CloudTrail AssumeRole eventsActual cross-account assumption activity with source account, role ARN, and timestamps
iam:GetServiceLastAccessedDetailsWhether the role was recently used
IAM Access AnalyzerExternal access findings — roles accessible from outside the account/organization

5. OIDC Federation Providers

What It Is

AWS IAM supports OIDC (OpenID Connect) identity providers as trusted identity sources. This allows external systems to exchange their identity tokens for AWS temporary credentials without long-lived access keys. The most common NHI patterns:

  • GitHub Actions OIDC: GitHub Actions workflows exchange GitHub-issued JWTs for AWS credentials via sts:AssumeRoleWithWebIdentity.
  • GitLab CI/CD OIDC: Same pattern, GitLab-issued JWTs.
  • Terraform Cloud/Enterprise: Terraform Cloud exchanges its workload identity token for AWS credentials.
  • EKS IRSA (covered in section 2.3): EKS cluster OIDC provider for pod identity.
  • Any OIDC-compliant IdP: Custom identity providers can be registered.

How It Authenticates

  1. The external system (e.g., GitHub Actions) issues a JWT (OIDC token) with claims about the identity (repository, branch, workflow, actor).
  2. The workload calls sts:AssumeRoleWithWebIdentity with the JWT and the target role ARN.
  3. The role's trust policy validates the JWT issuer (OIDC provider URL), audience, and optional subject/claim conditions.
  4. STS returns temporary credentials.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
IAM OIDC Providerconnectionoidc_provider
GitHub Actions workflowworkloadgithub_workflow (external, cross-system)
GitLab CI jobworkloadgitlab_ci_job (external, cross-system)
Terraform Cloud workspaceworkloadterraform_workspace (external, cross-system)
IAM Role (trusting the OIDC provider)identityiam_role
OIDC token exchangeexecution_evidencests_assume_role_web_identity

Relationships:

  • GitHub Workflow → AUTHENTICATES_VIA → OIDC Provider → TRUSTS → IAM Role

Security Risks

  • Overly broad OIDC trust conditions: The IAM role's trust policy does not restrict which repositories, branches, or environments can assume it. Example: "Condition": {"StringLike": {"token.actions.githubusercontent.com:sub": "repo:org-name/*"}} allows ANY repository in the organization to assume the role, including forks and new repos created by junior developers.
  • Missing audience restriction: The aud condition is not checked. Any token from the OIDC provider can be used.
  • No branch/environment pinning: The trust policy allows any branch to assume the role, not just main or production. A feature branch build can deploy to production.
  • GitHub Actions fork attack: If the repository allows workflows from forks, a malicious fork can trigger a workflow that assumes the IAM role.
  • Stale OIDC providers: The OIDC provider is registered but the corresponding external system no longer exists or has been reconfigured.

Realistic scenario: A team sets up GitHub Actions OIDC for deployment. The trust policy condition is "StringLike": {"token.actions.githubusercontent.com:sub": "repo:acme-corp/*:*"}. A developer creates a new repo acme-corp/test-sandbox with a workflow that assumes the deployment role and runs aws s3 ls s3://production-data-lake/. The role has s3:* on production buckets. SecurityV0 discovers: OIDC trust allows any repo in the org, authority path from any GitHub workflow to production S3, no branch/environment restriction.

Discovery APIs

APIData Returned
iam:ListOpenIDConnectProvidersAll registered OIDC providers with ARN
iam:GetOpenIDConnectProviderProvider URL, client IDs, thumbprints, creation date
IAM Role trust policy analysisRoles whose trust policy references the OIDC provider URL
CloudTrail AssumeRoleWithWebIdentity eventsActual OIDC-based role assumptions with source identity claims

6. SAML Federation (Entra ID / Okta SSO into AWS)

What It Is

AWS IAM supports SAML 2.0 identity providers for federated access. This is how enterprise SSO systems (Microsoft Entra ID, Okta, Ping Identity, ADFS) grant users access to AWS accounts. While SAML federation is primarily a human identity mechanism, it is relevant to NHI for several reasons:

  1. Federated users can create and manage NHIs — permission sets determine who can create roles, Lambda functions, etc.
  2. Service accounts in the IdP can federate into AWS just like human users.
  3. The IdP is the ownership source — when a human leaves the IdP, their ability to manage AWS workloads should also cease.

How It Authenticates

  1. User authenticates to the SAML IdP (Entra ID, Okta).
  2. IdP issues a SAML assertion with role ARNs the user is allowed to assume.
  3. The user/application calls sts:AssumeRoleWithSAML with the SAML assertion.
  4. STS validates the assertion against the SAML provider registered in IAM.
  5. STS returns temporary credentials for the specified role.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
SAML Identity Providerconnectionsaml_provider
Federated User/Service AccountidentityMapped to source IdP identity
IAM Role (trusting SAML provider)identityiam_role

Security Risks

  • Stale SAML provider configuration: The SAML provider metadata (certificate, endpoint) is outdated. If the IdP rotates certificates, AWS stops validating assertions correctly — but if the old certificate is not removed, old assertions may still work.
  • Broad role mapping: The SAML assertion maps all members of an IdP group to an AWS role with AdministratorAccess. When new members join the group, they automatically get full AWS access.
  • Service account federation: An Okta service account or Entra ID application can obtain SAML assertions programmatically (via Okta API, Entra ID SAML bearer grant). This turns a SAML federation into an NHI access path.

Discovery APIs

APIData Returned
iam:ListSAMLProvidersAll registered SAML providers
iam:GetSAMLProviderSAML metadata document, creation date, expiry
IAM Role trust policy analysisRoles trusting arn:aws:iam::ACCOUNT:saml-provider/PROVIDER_NAME
CloudTrail AssumeRoleWithSAML eventsActual SAML-based role assumptions

7. AWS IAM Identity Center (SSO)

What It Is

IAM Identity Center (formerly AWS SSO) is the recommended centralized access management service for AWS Organizations. It manages:

  • Identity source: Built-in directory, or external (Entra ID, Okta, etc.) via SCIM provisioning + SAML.
  • Permission sets: Named collections of IAM policies (e.g., AdministratorAccess, ViewOnlyAccess, custom).
  • Account assignments: Mappings of (user or group) → permission set → AWS account.

When a user accesses an account through Identity Center, a role is created in the target account (format: AWSReservedSSO_{PermissionSetName}_{random}) and the user assumes it.

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
Identity Center Instanceconnectionidentity_center
Permission Setrolesso_permission_set
Account AssignmentRelationship: ASSIGNED_TO (permission set → account)
User/Group in Identity Centeridentitysso_user / sso_group
Generated SSO Role in accountidentityiam_role (auto-managed)

Security Risks — NHI Relevance

  • Permission set drift: Permission sets are modified to add permissions for one team's need. Because the same permission set applies across multiple accounts, the change affects all assigned accounts.
  • Orphaned account assignments: A team is dissolved but their Identity Center group still has assignments to production accounts. The generated roles persist.
  • Over-assigned permission sets: A group of 50 engineers is assigned AdministratorAccess to 10 accounts "for convenience." Each of those 50 engineers can create, modify, or delete NHIs (IAM roles, Lambda functions, etc.) in those accounts.
  • Delegated admin misconfiguration: Identity Center can delegate admin to a non-management account. If the delegated admin account is compromised, the attacker controls all account assignments.
  • NHI management authority: Permission sets that include iam:*, lambda:*, or bedrock:* grant the ability to create and modify non-human identities. Tracking who has this authority is critical for NHI governance.

Discovery APIs

APIData Returned
sso-admin:ListInstancesIdentity Center instance(s)
sso-admin:ListPermissionSetsAll permission sets
sso-admin:DescribePermissionSetPermission set detail, session duration, relay state
sso-admin:GetInlinePolicyForPermissionSetInline policy on the permission set
sso-admin:ListManagedPoliciesInPermissionSetManaged policies in the permission set
sso-admin:ListAccountAssignmentsUser/group → permission set → account mappings
sso-admin:ListAccountsForProvisionedPermissionSetWhich accounts a permission set is deployed to
identitystore:ListUsersUsers in the Identity Center directory
identitystore:ListGroupsGroups in the Identity Center directory
identitystore:ListGroupMembershipsGroup memberships

8. Resource-Based Policies

What It Is

Several AWS services support resource-based policies — policies attached directly to a resource rather than to an identity. These policies can grant access to principals in other accounts without requiring a role assumption. They are a separate authority path that bypasses identity-based policy evaluation.

Key services with resource-based policies:

ServiceResourcePolicy API
S3Buckets3:GetBucketPolicy
KMSKeykms:GetKeyPolicy
LambdaFunctionlambda:GetPolicy
SQSQueuesqs:GetQueueAttributes (Policy attribute)
SNSTopicsns:GetTopicAttributes (Policy attribute)
Secrets ManagerSecretsecretsmanager:GetResourcePolicy
ECRRepositoryecr:GetRepositoryPolicy
API GatewayREST APIapigateway:GET /restapis/{id}/policy
EventBridgeEvent Busevents:DescribeEventBus
Step FunctionsState Machine (HTTP tasks)Defined in state machine definition
BedrockAgent / Knowledge BaseResource policy via bedrock:GetAgentPolicy etc.

SecurityV0 Entity Mapping

Resource-based policies create authority edges that are distinct from identity-based paths:

PatternSecurityV0
S3 bucket policy grants s3:GetObject to Account Bresource (S3 bucket) → GRANTS_ACCESS_TOidentity (principal in Account B)
Lambda resource policy allows EventBridge to invokeresource (Lambda) → INVOCABLE_BYworkload (EventBridge rule)
KMS key policy grants decrypt to Role Xresource (KMS key) → DECRYPTABLE_BYidentity (Role X)

Resource-based policies are important because they can grant access independently of the principal's identity-based policies. A principal with zero IAM permissions can still access a resource if the resource's policy allows it.

Security Risks

  • Public access: Resource policies with "Principal": "*" grant access to anyone, including unauthenticated principals (for S3 with ACLs disabled).
  • Cross-account grants without role assumption: A resource policy can grant access to an entire account ("Principal": {"AWS": "arn:aws:iam::EXTERNAL_ACCOUNT:root"}), meaning any identity in that account can access the resource.
  • Policy sprawl: Resource policies are managed per-resource, not centrally. Auditing them requires querying every resource individually.
  • KMS as implicit authority layer: Many resources are encrypted with KMS. Even if an identity has s3:GetObject permission, it also needs kms:Decrypt on the bucket's KMS key. Conversely, a KMS key policy that grants kms:Decrypt broadly creates an implicit authority expansion.

Discovery APIs

See the table above — each service has its own API for retrieving the resource policy. The connector must query each service individually.


9. Secrets Manager and Systems Manager Parameter Store

What It Is

AWS Secrets Manager stores, rotates, and manages secrets (database credentials, API keys, OAuth tokens). Secrets are encrypted with KMS and accessed via secretsmanager:GetSecretValue.

AWS Systems Manager Parameter Store stores configuration data and secrets. Parameters of type SecureString are encrypted with KMS. Accessed via ssm:GetParameter.

Both are critical for NHI because they store the credentials that workloads use to authenticate to non-AWS systems (databases, SaaS APIs, internal services).

SecurityV0 Entity Mapping

AWS ConceptSecurityV0 Entity TypeSubtype
Secrets Manager Secretcredentialsecrets_manager_secret
SSM SecureString Parametercredentialssm_secure_parameter
SSM String/StringList Parameterresourcessm_parameter
Secret rotation configurationProperty on the credential entity
KMS key used for encryptionresourcekms_key

Note: In the earlier AWS connector research, these were mapped as resource entities. For NHI-focused analysis, secrets that contain authentication credentials should be typed as credential entities, because they are the authentication mechanism for downstream access paths. The distinction: a credential is something a workload USES to authenticate; a resource is something a workload accesses as a destination.

Relationships:

  • workload → READS_SECRET → credential (Lambda env var references SECRET_ARN)
  • credential → AUTHENTICATES_TO → resource (the secret contains DB credentials for a specific database)
  • credential → ENCRYPTED_BY → resource (KMS key protecting the secret)
  • identity (IAM role) → CAN_READ → credential (via secretsmanager:GetSecretValue permission)

Security Risks

  • Unrotated secrets: Secrets Manager supports automatic rotation, but many secrets have rotation disabled. A 2-year-old database password is a significant risk.
  • Broad secret access: An IAM role has secretsmanager:GetSecretValue on Resource: * — it can read every secret in the account.
  • Resource policy on secrets: Secrets can have resource-based policies granting cross-account access. A secret containing production database credentials may be accessible from a dev account.
  • Environment variable exposure: Lambda functions reference secrets via environment variables (SECRET_ARN). If the Lambda role has lambda:GetFunctionConfiguration (meta-permissions), it can discover other functions' secret references.
  • Orphaned secrets: A secret was created for an integration that no longer exists. The secret still contains valid credentials that could be used if discovered.

Realistic scenario: A secrets rotation Lambda was set up for the production database password in Secrets Manager. The rotation Lambda's execution role was given secretsmanager:* and rds:* for convenience. The rotation Lambda failed 6 months ago (CloudWatch alarm was not set up). The secret has not been rotated in 6 months. The rotation Lambda's role still has write access to all secrets and all RDS instances. SecurityV0 discovers: stale credential (unrotated secret), overprivileged identity (rotation Lambda role), dormant workload (rotation Lambda not executing), and the production database password is 6 months old.

Discovery APIs

APIData Returned
secretsmanager:ListSecretsAll secrets with name, ARN, rotation config, last rotated date, last accessed date
secretsmanager:DescribeSecretSecret metadata, versions, rotation status, KMS key ID
secretsmanager:GetResourcePolicyResource-based policy on the secret
ssm:DescribeParametersAll parameters with type, tier, last modified
ssm:GetParametersByPathParameters under a path prefix with metadata
ssm:ListTagsForResourceTags on parameters

Important: The connector must NEVER call secretsmanager:GetSecretValue or ssm:GetParameter (for SecureString). The connector reads metadata only, never actual secret values.


10. AWS STS — Temporary Credentials and Session Tokens

What It Is

AWS Security Token Service (STS) is the service that issues temporary credentials for all role-based access. Every role assumption, federation, and cross-account access flows through STS.

STS operations:

OperationUse Case
AssumeRoleCross-account access, service-to-role, role chaining
AssumeRoleWithWebIdentityOIDC federation (GitHub Actions, EKS IRSA)
AssumeRoleWithSAMLSAML federation (Entra ID, Okta)
GetSessionTokenMFA-protected temporary credentials for IAM Users
GetFederationTokenCustom federated sessions (legacy pattern)
GetCallerIdentityReturns the identity of the caller — useful for debugging

SecurityV0 Entity Mapping

STS itself is not an entity — it is the mechanism by which identities are assumed and credentials are issued. STS events appear as execution_evidence:

STS EventSecurityV0 Entity TypeSubtype
AssumeRole callexecution_evidencests_assume_role
AssumeRoleWithWebIdentity callexecution_evidencests_assume_role_web_identity
AssumeRoleWithSAML callexecution_evidencests_assume_role_saml
Issued sessionTransient — not stored as entity, but the caller → role relationship is recorded

Security Risks

  • Session token persistence: Temporary credentials are valid for 1-12 hours. If exfiltrated, they are usable until expiry. Unlike access keys, they cannot be individually revoked (must revoke the role's sessions).
  • Session policy injection: AssumeRole can include an optional session policy that further restricts permissions. If the calling code does not use session policies, the assumed role gets its full permissions.
  • Role chaining duration limits: Chained role sessions are limited to 1 hour maximum, regardless of the role's MaxSessionDuration. This is a control, but it also means automation must handle credential refresh correctly.
  • Regional STS endpoint exposure: STS has a global endpoint and regional endpoints. Using regional endpoints reduces latency but also means CloudTrail events may be logged in different regions.

Discovery APIs

STS is primarily discovered through CloudTrail, not through direct API calls:

APIData Returned
CloudTrail events for sts:AssumeRoleSource principal, target role, session name, duration, source IP
CloudTrail events for sts:AssumeRoleWithWebIdentityOIDC provider, subject claim, audience
CloudTrail events for sts:AssumeRoleWithSAMLSAML provider, subject, role
sts:GetCallerIdentityCurrent caller identity (useful for connector self-check)

11. AWS NHI Security Features

11.1 IAM Access Analyzer

What it is: A service that analyzes resource policies and IAM policies to identify resources shared with external entities, unused access, and policy validation issues.

Two analyzer types:

  1. External access analyzer (zone of trust = organization or account): Identifies resources accessible from outside the zone of trust. Finds S3 buckets, IAM roles, KMS keys, Lambda functions, SQS queues, and Secrets Manager secrets that allow external access.

  2. Unused access analyzer: Identifies IAM roles and users with unused permissions, unused roles, and unused access keys. This is the highest-value signal for NHI scope drift detection.

SecurityV0 relevance:

  • External access findings map directly to scope_drift or reachability_drift findings in SecurityV0.
  • Unused access findings map to dormant_authority findings.
  • Access Analyzer findings can be ingested as pre-computed signals rather than re-deriving them from policy text.

Key APIs:

APIData Returned
accessanalyzer:ListAnalyzersAnalyzers configured in the account
accessanalyzer:ListFindingsFindings per analyzer — resource ARN, principal, condition, status
accessanalyzer:GetFindingFinding detail with resource policy analysis
accessanalyzer:ListAccessPreviewFindingsPreview of what findings would result from a policy change
accessanalyzer:GenerateAccessNotDecidableIdentifies policies that are ambiguous

Unused access analyzer specific APIs:

APIData Returned
accessanalyzer:ListFindingsV2Unused access findings — unused roles, permissions, access keys
Finding types: UnusedIAMRole, UnusedIAMUserAccessKey, UnusedIAMUserPassword, UnusedPermissionEach with last-accessed date and specific unused actions

11.2 IAM Credential Reports

What it is: A CSV report generated on demand containing security status for every IAM user in the account.

Fields include:

  • User ARN, creation time
  • Password enabled, last used, last changed, next rotation
  • Access key 1 & 2: active, last rotated, last used date, last used region, last used service
  • MFA active

SecurityV0 relevance: This is the single best API for discovering dormant IAM User NHIs. A user with access_key_1_last_used_date more than 90 days ago and access_key_1_active = true is a stale credential finding.

APIs:

APIData Returned
iam:GenerateCredentialReportTriggers report generation (asynchronous)
iam:GetCredentialReportReturns the CSV report

11.3 IAM Access Advisor (Service Last Accessed)

What it is: Provides data on when an IAM entity (user, role, group) last accessed each AWS service. This data is available for up to 400 days.

SecurityV0 relevance: If a role has s3:* permissions but the S3 service was last accessed 350 days ago, that is a strong signal for permission accumulation / dormant authority.

APIs:

APIData Returned
iam:GenerateServiceLastAccessedDetailsTriggers data generation for a specific entity
iam:GetServiceLastAccessedDetailsService name, last authenticated date, last authenticated entity, total authenticated entities
iam:GetServiceLastAccessedDetailsWithEntitiesWhich specific entities accessed a service

11.4 CloudTrail for Identity Activity

What it is: AWS CloudTrail logs every API call made in the account (management events by default, data events optionally). This is the primary source of execution_evidence for the SecurityV0 graph.

Priority CloudTrail events for NHI discovery:

EventNHI Signal
AssumeRoleRole assumption — who assumed what role, when, from where
AssumeRoleWithWebIdentityOIDC federation activity
AssumeRoleWithSAMLSAML federation activity
CreateRole, AttachRolePolicy, PutRolePolicyRole creation and permission changes
Invoke (Lambda)Lambda function execution
StartExecution (Step Functions)State machine execution
GetSecretValue (Secrets Manager)Secret access — highly sensitive
GetParameter (SSM)Parameter access
GetObject, PutObject (S3)Data access (data events — must be enabled)
CreateAccessKey, DeleteAccessKeyAccess key lifecycle
CreateUser, DeleteUserIAM user lifecycle
ConsoleLoginHuman activity (useful for NHI context — who manages what)

Organization trails: In multi-account setups, an organization trail logs events from all member accounts to a central S3 bucket. This is the preferred ingestion pattern for SecurityV0.

APIs:

APIData Returned
cloudtrail:DescribeTrailsTrail configuration, S3 bucket, SNS topic, log file validation
cloudtrail:GetTrailStatusWhether the trail is logging, last delivery time
cloudtrail:GetEventSelectorsWhich events are being logged (management, data)
S3 GetObject on trail bucketActual log files (compressed JSON)
Athena queries over trail S3 prefixAggregated event analysis

11.5 AWS Config Rules for IAM Compliance

What it is: AWS Config continuously evaluates resource configurations against rules. Several managed rules are relevant to NHI hygiene:

Config RuleNHI Signal
iam-user-unused-credentials-checkIAM users with unused credentials (customizable threshold)
iam-root-access-key-checkRoot account has active access keys
access-keys-rotatedAccess keys older than threshold (90 days default)
iam-policy-no-statements-with-admin-accessPolicies granting *:*
iam-policy-no-statements-with-full-accessPolicies granting service:*
iam-role-managed-policy-checkRoles missing required managed policies
iam-user-no-policies-checkIAM users with directly attached policies (vs group-based)
iam-no-inline-policy-checkEntities with inline policies
secretsmanager-secret-periodic-rotationSecrets without rotation
secretsmanager-secret-unusedUnused secrets
lambda-function-settings-checkLambda runtime, memory, timeout compliance

SecurityV0 relevance: AWS Config findings can be ingested as supporting evidence for SecurityV0 findings. They are not a primary discovery source but provide validation and compliance context.

APIs:

APIData Returned
config:GetComplianceDetailsByConfigRuleCompliance status per resource per rule
config:DescribeComplianceByConfigRuleSummary compliance per rule
config:GetResourceConfigHistoryResource configuration changes over time

12. Comprehensive Ownership Decay Scenarios

This section consolidates the most important ownership decay patterns across all AWS NHI types into a reference catalog for SecurityV0 finding design.

12.1 The Departed Engineer Pattern

Trigger: Human leaves the organization.

Decay chain:

  1. Engineer created IAM roles, Lambda functions, Step Functions state machines.
  2. Engineer's human IAM account or SSO access is deactivated (HR offboarding).
  3. The NHIs the engineer created continue operating autonomously.
  4. Nobody knows they exist, what they do, or why they have the permissions they have.
  5. Over time, automated processes attach additional policies to these NHIs to fix integration issues.
  6. The NHIs accumulate permissions far beyond their original scope.

SecurityV0 detection: ownership_status: orphaned + execution_30d > 0 (actively executing but no owner).

12.2 The Accumulated Permission Pattern

Trigger: Incremental policy changes over months/years.

Decay chain:

  1. Role is created with minimal permissions for a specific workload.
  2. Feature requests require new permissions — each added incrementally.
  3. Old permissions are never reviewed or removed.
  4. The role accumulates 15 managed policies and 3 inline policies over 2 years.
  5. The effective permission set is s3:*, dynamodb:*, lambda:*, secretsmanager:*, sqs:* on Resource: *.
  6. The workload only uses 4 specific S3 buckets and 2 DynamoDB tables.

SecurityV0 detection: scope_drift finding. Access Advisor shows services last accessed, IAM Access Analyzer shows unused permissions.

12.3 The Decommissioned Workload Pattern

Trigger: Business process changes, workload is superseded.

Decay chain:

  1. A Lambda function processes daily reports.
  2. The team migrates to a new reporting system.
  3. The old Lambda function is not deleted — "just in case."
  4. The EventBridge rule still triggers the function daily.
  5. The function fails silently (the target API was decommissioned).
  6. The function's execution role retains broad permissions to production data.
  7. Two years later, nobody remembers the function exists.

SecurityV0 detection: dormant_authority finding — role has broad permissions but Access Advisor shows no service access. Or: execution evidence shows the function is invoked but returns errors (evidence of purposeless execution).

12.4 The Vendor Trust Decay Pattern

Trigger: Third-party vendor relationship changes.

Decay chain:

  1. Cross-account role is created for a vendor with ReadOnlyAccess.
  2. Vendor needs write access for a project — PowerUserAccess is added.
  3. Project ends. The additional permissions are not removed.
  4. Vendor contract is not renewed. The trust policy is not removed.
  5. Vendor's AWS account still has assume-role access to the customer's production account with PowerUserAccess.

SecurityV0 detection: Cross-account trust to external account + no recent execution evidence + no owner assigned.

12.5 The Scope Creep via Shared Role Pattern

Trigger: Multiple workloads sharing one role.

Decay chain:

  1. A role is created for Lambda Function A.
  2. Lambda Function B needs similar access, so it reuses the same role.
  3. Function B needs additional S3 access — added to the shared role.
  4. Function C joins the shared role and needs DynamoDB access — added.
  5. Now Functions A, B, and C all have S3 + DynamoDB + original permissions.
  6. Function A only needs the original permissions.

SecurityV0 detection: Identity Access Surface shows 3 workloads sharing one identity with 5+ roles and permissions exceeding any individual workload's need.

12.6 The OIDC Federation Scope Expansion Pattern

Trigger: Organization adds repositories, teams, or CI/CD pipelines.

Decay chain:

  1. GitHub OIDC is configured with trust for repo:org/infra-repo:ref:refs/heads/main.
  2. A new team needs deployment access — trust is broadened to repo:org/*:*.
  3. Any new repository in the org can now assume the deployment role.
  4. A junior developer creates a test repo with a workflow that assumes the role.
  5. The test workflow has access to production deployment permissions.

SecurityV0 detection: OIDC trust condition analysis shows wildcard patterns. Cross-reference with the list of repos that have actually assumed the role (from CloudTrail) to show the gap between intended and actual scope.


13. AWS API Coverage Summary for Connector

This table summarizes all AWS APIs the connector needs for comprehensive NHI discovery:

Core IAM APIs (all identities)

iam:ListUsers, iam:GetUser, iam:ListAccessKeys, iam:GetAccessKeyLastUsed
iam:ListRoles, iam:GetRole, iam:ListRolePolicies, iam:GetRolePolicy
iam:ListAttachedRolePolicies, iam:ListAttachedUserPolicies
iam:GetPolicy, iam:GetPolicyVersion
iam:ListInstanceProfiles, iam:GetInstanceProfile
iam:ListGroupsForUser, iam:ListGroups, iam:GetGroup
iam:ListMFADevices
iam:ListOpenIDConnectProviders, iam:GetOpenIDConnectProvider
iam:ListSAMLProviders, iam:GetSAMLProvider
iam:ListRoleTags, iam:ListUserTags
iam:GenerateCredentialReport, iam:GetCredentialReport
iam:GenerateServiceLastAccessedDetails, iam:GetServiceLastAccessedDetails

Workload APIs

lambda:ListFunctions, lambda:GetFunction, lambda:GetPolicy, lambda:ListEventSourceMappings
ecs:ListClusters, ecs:DescribeClusters, ecs:ListServices, ecs:DescribeServices
ecs:ListTaskDefinitions, ecs:DescribeTaskDefinition
eks:ListClusters, eks:DescribeCluster, eks:ListPodIdentityAssociations, eks:DescribePodIdentityAssociation
states:ListStateMachines, states:DescribeStateMachine
events:ListRules, events:ListTargetsByRule, events:DescribeRule
glue:GetJobs, glue:GetCrawlers, glue:GetConnections
sagemaker:ListNotebookInstances, sagemaker:ListEndpoints, sagemaker:ListTrainingJobs
codebuild:ListProjects, codebuild:BatchGetProjects
codepipeline:ListPipelines, codepipeline:GetPipeline
emr:ListClusters, emr:DescribeCluster
redshift:DescribeClusters
bedrock:ListAgents, bedrock:GetAgent, bedrock:ListKnowledgeBases, bedrock:GetKnowledgeBase
bedrock:ListFlows, bedrock:GetFlow, bedrock:ListAgentActionGroups

Resource / Credential APIs

s3:ListAllMyBuckets, s3:GetBucketPolicy, s3:GetBucketAcl, s3:GetBucketLocation
s3:GetBucketEncryption
secretsmanager:ListSecrets, secretsmanager:DescribeSecret, secretsmanager:GetResourcePolicy
ssm:DescribeParameters, ssm:GetParametersByPath, ssm:ListTagsForResource
kms:ListKeys, kms:DescribeKey, kms:GetKeyPolicy, kms:ListAliases
ecr:DescribeRepositories, ecr:GetRepositoryPolicy
dynamodb:ListTables, dynamodb:DescribeTable
rds:DescribeDBInstances, rds:DescribeDBClusters
sqs:ListQueues, sqs:GetQueueAttributes
sns:ListTopics, sns:GetTopicAttributes

Organization / Identity Center APIs

organizations:ListAccounts, organizations:DescribeOrganization
organizations:ListOrganizationalUnitsForParent, organizations:DescribeOrganizationalUnit
organizations:ListPolicies, organizations:DescribePolicy
sso-admin:ListInstances, sso-admin:ListPermissionSets, sso-admin:DescribePermissionSet
sso-admin:ListAccountAssignments, sso-admin:GetInlinePolicyForPermissionSet
sso-admin:ListManagedPoliciesInPermissionSet
identitystore:ListUsers, identitystore:ListGroups, identitystore:ListGroupMemberships

Security Feature APIs

accessanalyzer:ListAnalyzers, accessanalyzer:ListFindings, accessanalyzer:GetFinding
config:GetComplianceDetailsByConfigRule, config:DescribeComplianceByConfigRule
cloudtrail:DescribeTrails, cloudtrail:GetTrailStatus, cloudtrail:GetEventSelectors

Evidence APIs (CloudTrail via S3)

s3:GetObject, s3:ListBucket (on CloudTrail bucket only)
athena:StartQueryExecution, athena:GetQueryExecution, athena:GetQueryResults

14. Entity Mapping Summary Table

This is the complete mapping from AWS NHI types to SecurityV0 entities:

AWS NHI / ConceptSecurityV0 Entity TypeSubtypePriority
IAM User (programmatic)identitymachine_accountPhase 1
IAM Roleidentityiam_rolePhase 1
IAM Groupidentityiam_groupPhase 1
Service-Linked Roleidentityservice_linked_rolePhase 2
IAM Managed Policypermissioniam_policyPhase 1
IAM Inline Policypermissioniam_inline_policyPhase 1
SSO Permission Setrolesso_permission_setPhase 3
Permission statementpermissioniam_permissionPhase 1
Access Key paircredentialaws_access_keyPhase 1
Secrets Manager Secretcredentialsecrets_manager_secretPhase 1
SSM SecureString Parametercredentialssm_secure_parameterPhase 1
Lambda Functionworkloadlambda_functionPhase 1
Step Functions State Machineworkloadstep_functionPhase 1
ECS Task Definition / Serviceworkloadecs_task / ecs_servicePhase 2
EKS Workloadworkloadeks_workloadPhase 2
EC2 Instanceworkloadec2_instancePhase 3
Bedrock Agentworkloadbedrock_agentPhase 1
Bedrock Flowworkloadbedrock_flowPhase 1
Glue Jobworkloadglue_jobPhase 3
SageMaker Notebook/Endpointworkloadsagemaker_*Phase 3
CodeBuild Projectworkloadcodebuild_projectPhase 2
CodePipeline Pipelineworkloadcodepipeline_pipelinePhase 2
EMR Clusterworkloademr_clusterPhase 3
Redshift Clusterworkloadredshift_clusterPhase 3
OIDC Providerconnectionoidc_providerPhase 2
SAML Providerconnectionsaml_providerPhase 3
Identity Center Instanceconnectionidentity_centerPhase 3
EventBridge Connectionconnectioneventbridge_connectionPhase 1
S3 Bucketresources3_bucketPhase 1
DynamoDB Tableresourcedynamodb_tablePhase 1
RDS Instance/Clusterresourcerds_instancePhase 2
SQS Queueresourcesqs_queuePhase 2
SNS Topicresourcesns_topicPhase 2
ECR Repositoryresourceecr_repositoryPhase 2
KMS Keyresourcekms_keyPhase 2
AWS AccountTenant contextaws_accountPhase 0
Organizational UnitTenant contextaws_ouPhase 0
CloudTrail eventexecution_evidencecloudtrail_eventPhase 1
IAM Access Analyzer findingConnector metadata (not an entity — see note below)access_analyzer_findingPhase 1

Next Action

Status: research-complete

Decision needed from: PO / CTO (Ivan)

Recommended action: Use this catalog as the authoritative reference for AWS connector entity mapping. The phasing aligns with the AWS Integration Strategy.

Design decisions resolved:

  1. Secrets Manager / SSM secrets → credential. These are authentication material that workloads USE to authenticate downstream — they participate in the execution chain via USES edges. Modeling as resource would miss credential-chain patterns.

  2. OIDC / SAML providers → connection. These are outbound integration configurations (like ServiceNow REST Messages), not identities themselves. They enable the AUTHENTICATES_TO edge between systems.

  3. IAM Managed Policies → permission. A policy document contains permission statements (Allow/Deny on Actions+Resources). This maps to the permission entity type, not role. IAM roles are the identity-bearing entity that HAS permissions — the policy is the permission grant itself.

  4. IAM Access Analyzer findings → connector metadata, not execution_evidence. Access Analyzer output is derived posture analysis ("this role has unused permissions"), not proof of observed execution activity. It feeds the connector's evidenceCompleteness metadata and helps generate SecurityV0 findings, but does not become an execution_evidence entity. CloudTrail events and service-last-accessed data ARE execution evidence.

GitHub Issue: not yet created — create in sv0-connectors after strategy adoption.


Sources