Skip to content

Generate Resource Access Paths

Note: This is a draft API and is subject to change.

k9 reports which principals have direct access to resources such as IAM roles and S3 buckets. But it is also useful to know what principals have indirect access to the resource by assuming a role that has direct access.

Suppose you want to know which principals can use the 333-dst-1 role, a IAM admin in the production account in the example below, and are thus 'indirect' admins of account 333:

Example of an IAM role with several access paths
Figure 1. Many paths to access the 333-dst-1 IAM role

Partners can generate a list of access paths for one or more resources in an account using the k9 API with:

POST /partner/{partnerId}/customer/{partnerCustomerId}/account/{accountId}/resource-access-paths

In the example, k9 will return the following access paths both within and across accounts to 333-dst-1:

  1. 333-dst-1 has access
  2. 333-src-1 has access
  3. 333-src-2 has access via 333-src-1
  4. 333-src-3 has access via 444-src-1 and the 444 account trust
  5. 222-int-1 has access
  6. 111-src-1 has access via 222-int-1
  7. 111-src-2 has access
  8. 111-src-3 has access via 111-src-2
  9. 444 has access
  10. 444-src-1 has access via trust of account 444
  11. 555 has access via 111-src-4 (trusts 555) and 222-int-1
  12. 555-src-1 has access via 111-src-4 (trusts 555) and 222-int-1

(Note: k9 Security & AWS IAM Access Analyzer must be enabled on all accounts)

Request Headers

Set the Content-Type header to application/json

Request Path Parameters

The generate resource access paths API requires three path parameters:

partnerId: the k9 Partner ID that manages the account, e.g. P123456.

Type: String

Pattern: P[\d]{6}

partnerCustomerId: the partner's own unique customer or tenant identifier for the managed customer environment, e.g. a UUID, AWS Organization ID, SHA256 digest

Type: String

Pattern: [\w-_.]{6,64}

account_id: the AWS account ID the resources belong to, e.g. 123456789012

Type: String

Pattern: [\d]{12}

Request Body

Populate the request body with a json document like:

{
  "resourceIds": [
    "arn:aws:iam::333:role/333-dst-1",
    "arn:aws:iam::333:role/333-src-1"
  ],
  "service": "STS",
  "principalAccessCapabilities": [
    "use-resource"
  ],
  "accessCapabilityOperator": "OR"
}

The request body contains several elements:

resourceIds: (required) is a list of the canonical resource identifiers for the platform: an ARN in AWS, a UUID in Azure

principalAccessCapabilities: (required) is a list of k9 access capabilities for which the client is looking for principals that have access to the resource, i.e. in the example, this query is looking for principals that can use the 333-dst-1 or 333-src-1 roles.

service (required) specifies k9’s name for the cloud service that you are looking for access to the resource. In most cases, this is the same as the service hosting the resource itself, e.g. an S3 bucket's service name is S3. However, some resources such as IAM roles are accessed via another service such as STS. Currently supported values: STS

accessCapabilityOperator: (required) when multiple principalAccessCapabilities are specified, determines whether the API will return principal access paths to a resource when any ("OR") specified capabilities exist or if the principal must have all specified capabilities ("AND"). Supported values: OR, AND

maxAccessPathNodes: (optional) configures the maximum number of nodes to resolve when generating resource access paths. Default: 10, Minimum: 1, Maximum: 15

Response

Success

When you successfully generate access paths for a list of resources, the API will respond with:

Response Status Code: 200 (Success)

Response Body (Example):

{
  "resourceAccessPaths": {
    "arn:aws:iam::333:role/333-dst-1": {
      "resourceType": "IAMRole",
      "accessPaths": [
        {
          "nodes": [
            "arn:aws:iam::333:role/333-dst-1"
          ],
          "truncated": false,
          "cycle": true
        },
        {
          "nodes": [
            "arn:aws:iam::333:role/333-src-1"
          ],
          "truncated": false,
          "cycle": false
        },
        {
          "nodes": [
            "arn:aws:iam::333:role/333-src-1",
            "arn:aws:iam::333:role/333-src-2"
          ],
          "truncated": false,
          "cycle": false
        },
        {
          "nodes": [
            "arn:aws:iam::111:role/111-src-2"
          ],
          "truncated": false,
          "cycle": false
        },
        {
          "nodes": [
            "arn:aws:iam::111:role/111-src-2",
            "arn:aws:iam::111:role/111-src-3"
          ],
          "truncated": false,
          "cycle": false
        },
        {
          "nodes": [
            "arn:aws:iam::222:role/222-int-1"
          ],
          "truncated": false,
          "cycle": false
        },
        {
          "nodes": [
            "arn:aws:iam::222:role/222-int-1",
            "arn:aws:iam::111:role/111-src-1"
          ],
          "truncated": false,
          "cycle": false
        },
        {
          "nodes": [
            "arn:aws:iam::222:role/222-int-1",
            "arn:aws:iam::111111111111:role/111-src-4", 
            "555555555555"
          ],
          "truncated": false,
          "cycle": false
        },
        {
          "nodes": [
            "arn:aws:iam::222:role/222-int-1",
            "arn:aws:iam::111111111111:role/111-src-4", 
            "555555555555",
            "arn:aws:iam::555555555555:role/555-src-1"
          ],
          "truncated": false,
          "cycle": false
        },
        {
          "nodes": [
            "444"
          ],
          "truncated": false,
          "cycle": false
        },
        {
          "nodes": [
            "444",
            "arn:aws:iam::444:role/444-src-1"
          ],
          "truncated": false,
          "cycle": false
        },
        {
          "nodes": [
            "444",
            "arn:aws:iam::444:role/444-src-1",
            "arn:aws:iam::333333333333:role/333-src-3"
          ],
          "truncated": false,
          "cycle": false
        }
      ]
    },
    "arn:aws:iam::333:role/333-src-1": {
      "resourceType": "IAMRole",
      "accessPaths": []
    }
  }
}

The resourceAccessPaths element contains a map keyed by the resource ids specified in the request. The value for each resource id entry is an object describing the resource type and the access paths to it.

resourceType is the k9-defined resource type for the resource as used in the Resources view, e.g. IAMRole or S3Bucket.

accessPaths is an array of access paths to the resource. An access path is an object that describes the path with the following members:

  • nodes is a list of principal ids that form a path to the target resource. The list starts with the node that is adjacent to the target resource and continues with nodes of increasing degree until the leaf node of the access path or the length of the path reaches maxAccessPathNodes. When a circular access path is detected, the final entry in the array will be the resource causing the cycle, and the cycle member will be true. An example of this is arn:aws:iam::333:role/333-dst-1's first access path showing it can assume itself.
  • truncated is a boolean indicating whether expansion of the list of nodes was truncated due to the maxAccessPathNodes limit.
  • cycle: is a boolean indicating whether a cycle was found.

When no principals can use the resource with the defined capabilities, then the accessPaths array will be empty. For example, 333-src-1 can not be used by any other roles, users, or accounts and so its accessPaths array is empty.

Note: Each navigable access path is reported as its own access path from each potential starting point to simplify rendering logic. So ["arn:aws:iam::111:role/111-src-3"] is reported distinctly from ["arn:aws:iam::111:role/111-src-2", "arn:aws:iam::111:role/111-src-3"].

Not Authorized

If the calling principal is not authorized to generate resource access paths, the API will respond with:

Response Status Code: 403 (Forbidden)

Response Body (Example):

{
  "message": "Caller is not authorized to generate resource access paths."
}

Last update: June 12, 2024