Identity and access management

Identity and Access Management (IAM) is a system that defines how users access a platform's resources. StackPath's IAM system defines a user's access to their account or to the stacks on their account. Operations in StackPath's customer portal and API are validated against the IAM system before they're executed.

Concepts

Users

A user is anyone that can login to the StackPath customer portal or use the StackPath API. The IAM system manages policies assigned to resources, which in turn control that user's access to the platform. A relationship between a user and what they can do in the platform is called a binding.

Every StackPath account has a default "root" user that has full access to everything on the account and the account's stacks. That access cannot be taken away.

🚧

Users have an ID but are identified by their email address in the IAM system.

Resources

A resource is any service or feature that StackPath provides. Resources can exist account-wide like billing and user management or they can be stack-based like sites, compute workloads, and DNS zones.

Policies

A policy associates roles to users. Policies exist for an account or a stack on an account. Accounts and stacks have one policy, but that policy can have multiple bindings to allow fine-grained user and role control.

Stacks don't have policies when they're created, but we encourage you to create stack-based policies to meet your organization's needs.

Roles

A role is a collection of permissions that is applied to a StackPath account or stack. Users are assigned roles instead of individual permissions as policy bindings.

StackPath's IAM system has two pre-defined global roles:

  • roles/systemOwner: The user has full access their account and all of the account's stacks. An account's root user has this role by default, and this role cannot be removed.
  • roles/systemAdmin: The user has access to everything on their account and stack except billing user related services. This role is useful for resellers who want to assign stacks to their clients while hiding billing information. We suggest applying this role to non-root users.

Every service in the StackPath platform has pre-defined viewer and admin roles to assign read and read/write permissions to those services. These roles are named according to their associated service:

To manage

Pre-defined roles

Accounts and users

roles/identityViewer
roles/identityAdmin

Stacks

roles/stackViewer
roles/stackAdmin

Account and stack IAM policies

roles/policyViewer
roles/policyAdmin

Sites
Content delivery network
Web application firewall

roles/deliveryViewer
roles/deliveryAdmin

DNS

roles/dnsViewer
roles/dnsAdmin

Edge compute

roles/workloadViewer
roles/workloadAdmin

Edge compute networking

roles/ipamViewer
roles/ipamAdmin

SSL

roles/sslViewer
roles/sslAdmin

Monitoring

roles/monitoringViewer
roles/monitoringAdmin

Object storage

roles/storageViewer
roles/storageAdmin

Viewing stack and account policies

Place an HTTP GET request to the /identity/v1/accounts/YOUR_ACCOUNT_ID/iam/policy or /stack/v1/stacks/YOUR_STACK_SLUG/iam/policy endpoints to see the account or stack's IAM policy:

$ curl --request GET \
  --url https://gateway.stackpath.com/stack/v1/stacks/YOUR_STACK_SLUG/iam/policy \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: bearer YOUR_BEARER_TOKEN'

If the stack has an IAM policy then the call returns a response with the stack's policy bindings:

HTTP/1.1 200 OK
Date: Wed, 12 Aug 2020 00:05:54 GMT
Content-Type: application/json
Content-Length: 215
Connection: keep-alive
Strict-Transport-Security: max-age=15724800; includeSubDomains
Grpc-Metadata-Content-Type: application/grpc

{
  "stackId": "74dd3b65-5f01-4b1e-8fcc-ad8443568af7",
  "policy": {
    "bindings": [
      {
        "role": "roles/dnsViewer",
        "members": [
          "user:[email protected]",
          "user:[email protected]"
        ]
      }
    ],
    "version": 0,
    "createdAt": "2020-08-12T00:05:54.604071Z"
  }
}

An IAM policy has the following properties:

  • accountId or stackId: The account or stack's unique ID
  • policy: The policy bound to the account or stack. Every policy has the properties:
    • bindings: The bindings associated with the policy
      • role: The role applied in the policy binding
      • members: The users associated with the binding's role. Members are prefaced with "user:" and are identified by the user's email address
    • version: The policy's version. Version numbers start at 0 and are incremented every time the policy changes
    • createdAt: The date the policy was created

Account policies are applied to every API call. Stack policies don't override account policies, but they can make access to the stack more permissible.

If a stack doesn't have an IAM policy then querying for it produces a 404 Not Found error response:

HTTP/1.1 404 Not Found
Date: Tue, 11 Aug 2020 22:49:11 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Strict-Transport-Security: max-age=15724800; includeSubDomains

{
  "code": 5,
  "message": "Policy not found",
  "details": [
    {
      "@type": "stackpath.rpc.RequestInfo",
      "requestId": "1bed05b22a509092",
      "servingData": ""
    }
  ]
}

Setting policies

Send an HTTP PUT call to the /identity/v1/accounts/YOUR_ACCOUNT_ID/iam/policy or /stack/v1/stacks/YOUR_STACK_SLUG/iam/policy endpoints to update your account's or stack's policy. The body of the request should contain the full policy to apply. This example adds the user [email protected] with the role roles/systemAdmin to the stack policy described above. Remember to increment the policy's version in the request:

$ curl --request PUT \
  --url https://gateway.stackpath.com/stack/v1/stacks/YOUR_STACK_SLUG/iam/policy \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: bearer YOUR_BEARER_TOKEN' \
  --data '{
  "policy": {
    "bindings": [
      {
        "role": "roles/dnsViewer",
        "members": [
          "user:[email protected]",
          "user:[email protected]"
        ]
      },
      {
        "role": "roles/systemAdmin",
        "members": [
          "user:[email protected]"
        ]
      }
    ],
    "version": 1
  }
}'

When successful, the call returns new policy back to the caller:

HTTP/1.1 200 OK
Date: Wed, 12 Aug 2020 00:05:54 GMT
Content-Type: application/json
Content-Length: 215
Connection: keep-alive
Strict-Transport-Security: max-age=15724800; includeSubDomains
Grpc-Metadata-Content-Type: application/grpc

{
  "stackId": "74dd3b65-5f01-4b1e-8fcc-ad8443568af7",
  "policy": {
    "bindings": [
      {
        "role": "roles/dnsViewer",
        "members": [
          "user:[email protected]",
          "user:[email protected]"
        ]
      },
      {
        "role": "roles/systemAdmin",
        "members": [
          "user:[email protected]",
        ]
      },
    ],
    "version": 2,
    "createdAt": "2020-08-12T00:05:54.604071Z"
  }
}

Removing a stack's policy

You cannot remove an account's policy, but you can remove a stack's policy to have its access revert to your account's policy. Send an HTTP DELETE call to /stack/v1/stacks/YOUR_STACK_SLUG/iam/policy to remove the policy:

$ curl --request DELETE \
  --url https://gateway.stackpath.com/stack/v1/stacks/YOUR_STACK_SLUG/iam/policy \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: bearer YOUR_BEARER_TOKEN'

The call returns a 204 No Content response on success:

HTTP/1.1 204 No Content
Date: Fri, 14 Aug 2020 21:21:17 GMT
Connection: keep-alive
Strict-Transport-Security: max-age=15724800; includeSubDomains
Grpc-Metadata-Content-Type: application/grpc

Error handling

API calls return a 403 Forbidden response If a user does not have permission to access the requested resource or perform the requested operation. See Error handling for more information on StackPath API errors.

HTTP/1.1 403 Forbidden
Date: Tue, 11 Aug 2020 22:15:02 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Strict-Transport-Security: max-age=15724800; includeSubDomains

{
  "code": 7,
  "message": "Permission denied",
  "details": [
    {
      "@type": "stackpath.rpc.RequestInfo",
      "requestId": "dc33b2f909b1c79a",
      "servingData": ""
    }
  ]
}