Using the Secrets API with Okta Privileged Access

Okta Privileged Access has the ability to store and retrieve generic secrets in it’s vault. This can be done via the user interface, the sft client in the command line or via the Secrets API. This article will explore the Secrets API for managing secrets in the vault.

Overview

Secrets management involves both folders (and a folder hierarchy) and the secrets stored in a folder. Access to (and maintenance of) the folders and secrets is controlled by Security Policy in Okta Privileged Access. More information on secrets, folders and management can be found in the Secrets section of the product documentation. Folders and secrets can be managed in the Okta Privileged Access user interface, via the client (sft) or by using the API. This article is focused on the APIs.

Most of these APIs can be implemented in Okta Workflows leveraging either a Generic API (HTTP) Connector or the new Okta Privileged Access Connector. Some APIs require use of JSON Web Encrypted (JWE) secrets and as Okta Workflows does not have mechanism to encrypt/decrypt JWEs, the Create/Update/Reveal a Secret APIs cannot be run in Okta Workflows.

Secrets API

There are a set of Secrets APIs available to programmatically access and manage the secrets and folders.

When working with secrets/folders, there are two hierarchies you may need to contend with – the resource group/project structure and the folder hierarchy attached to specific resource groups/projects. The following figure shows multiple resource groups, one with multiple projects. Within each project, there is a hierarchy of secret folders.

You will normally need the secret id (or folder id) with the APIs to manage a secret/folder. In many cases you need to only know the resource group and project id’s to find the relevant secret/folder. However some APIs require traversing or navigating a folder structure within a specific resource group/folder. This is covered when discussing the different APIs in following sections.

Top-level Folders APIs

When we talk about folders we often distinguish between top-level folders and other folders. Top-level folders are attached to a Project in a Resource Group and are the top of any tree hierarchy. Other folders are attached to the top-level or other folders to create that hierarchy.

There are three APIs specifically for top-level folders:

  • List top-level Secret Folders for a Project – list all top-level folders in a project, returning an array that includes the id, name and description of the folders. For example, if this was run for Project BB in the above diagram, it would return a list with Top-level Folder 3, Top-level Folder 3A, and Top-level Folder 3B.
  • List top-level Secret Folders for a Team – list ALL top-level folders in an Okta Privileged Access team. It returns the id, name and description, along with information about the resource group and project. As most other folder/secret APIs need the Id of the resource group and project, this API call may be useful in a search function. In the example above it would return a list with all six Top-level Folders (1, 2, 3, 3A, 3B, 4).
  • List top-level Secret Folders for User – list ALL top-level folders for a user. Note that this API does not allow for a user to be specified and just uses the service user making the API call, so it may not provide a lot of value.

There are no CRUD APIs specifically for top-level folders. You use the folder APIs to create, read. update and delete top-level folders (see below). To use the create API to create a top-level folder, you do not specify a parent_folder_id in the body.

Folders APIs

The folders APIs are:

  • Create a Secret Folder – create a folder in a project. If a parent_folder_id is specified it will place the new folder under the specified parent, otherwise it will create a top-level folder. The response will include the id of the new folder and it’s path (an array representing the hierarchy).
  • Retrieve a Secret Folder – this will return the name, description and create/update info for a folder.
  • Update a Secret Folder – this allows updating the name and optionally the description of a folder.
  • Delete a Secret Folder – this deletes a secret folder.
  • List all items in a Secret Folder – list all items (secrets and folders) in a folder. Note that this is a “single-level” search – it only returns the items at this level (it does not recursively search through sub folders). This API supports pagination.

There is no Team-wide search API available. If you need to find a folder (or a secret within it) you will need to traverse the folder hierarchy, starting with the list of top-level folders and using the List all items API on each.

Secrets APIs

There are five APIs for working with secrets:

  • Create a Secret – this will take an encrypted secret value and store it in the vault, associated with a resource group, project and folder.
  • Retrieve a Secret – this will get details of a secret, such as name and description, created/updated details, and path. Note that you don’t need to traverse the folder structure to find the specific secret, you just specify the resource group, project and secret ids (which can be found using the Resolve Secret or Folder API).
  • Reveal a Secret – whereas the Retrieve API will provide details of the secret, it does not show the secret values. The Reveal API is passed a public key which is used to encrypt the secret values and return them.
  • Update a Secret – update the name, description and/or secret value of a secret.
  • Delete a Secret – delete the secret.

Most of these are straightforward to use. However the Create, Reveal and Update APIs need to work with public/private keys and JSON Web Encryption (JWE) secrets (i.e. requiring encryption/decryption of secrets). This is explored in more detail below.

Common APIs for Secrets and Folders

There is a single API that applies to both secrets and folders – Resolve Secret or Folder. You tell it where the secret or folder is and it will return the id of the secret or folder.

It has limited value as it’s not a search function – you need to know where the secret/folder is to use it. But it does mean you don’t need to traverse the folder hierarchy, just the resource group/project hierarchy to find the right one. For example if you ran it against Resource Group B / Project BB (in the figure above) it would search for a secret across all seven folders in that project. Thus to search you could list all resource groups (here) and projects in them (here) and then use this Resolve API to search in each RG/Project pair.

Creating, Updating and Revealing Secrets

Whilst most of the APIs are reasonably simple to use, the Create/Update a Secret and Reveal a Secret APIs are more complicated as they require JWE encryption/decryption capabilities.

The following diagram shows the main flows between a client (where the APIs are run from) and Okta Privileged Access when using the Create/Update/Reveal a Secret APIs.

There are two sets of flows:

  1. The top set (orange arrows) show the flows to create or update a secret, which require obtaining the public key from Okta Privileged Access to encrypt the secret.
  2. The bottom set (green arrows) show the flows to reveal a secret, which require creating a private/public key pair, passing the public key to Okta Privileged Access so it can encrypt the secret, then using the private key to decrypt the secret in the client.

These flows will be described in the following sections.

Conventions with Keys and Encryption

There are some common conventions around the keys and encryption that may not be clear in the product documentation:

  • The create and update options use the public key from the Okta Privileged Access team. This is downloaded using the /v1/teams/:team_name/vault/jwks.json endpoint.
  • The Okta Privileged Access public key uses a RSA key type with the RSA-OAEP-256 algorithm. Any private/public key pair you use should also use this. Key size of 2048 is ok. I don’t think the key id is actually used.
  • The encrypted secret (provided by Okta Privileged Access in a reveal operation, or passed to Okta Privileged Access in a create or update operation) is a fully serialized JWE. The two serialization options are described in the JSON Web Encryption (JWE) Overview section of the RFC. The default for many JWE libraries is for compact serialization. The Okta Privielged Access APIs require full serialization, which in the spec is referred to as JWE JSON Serialization.

The following sections will expand on the flows and provide examples of keys and encryption used.

Encrypt and Create/Update a Secret

The process involved in creating (or updating) a secret is shown in the top half of the diagram above.

The first step is to get the public key from your instance of Okta Privileged Access. This only needs to be done once as the public key will not change. An example jwks.json file is shown below.

Once this file is downloaded, the steps to create (or update) a secret are:

  1. Use this public key to encrypt the secret into a fully serialized JWE
  2. Use the Create a Secret (or Update a Secret) API to upload the encrypted secret to Okta Privileged Access
  3. Okta Privileged Access will decrypt the secret_jwe with its private key and store it in the vault

When the public key is used to encrypt the secret into a fully serialized JWE, it will look something like the following (containing “protected”, “encrypted_key”, “iv”, “ciphertext” and “tag” fields).

This is then passed to the Create/Update a Secret API in the body along with the secret name and parent_folder_id.

If the operation is successful, you should be able to reveal the secret in the Okta Privileged Access user interface.

Reveal and Decrypt a Secret

The process involved in revealing and decrypting a secret is shown in the bottom half of the diagram above and has three basic steps:

  1. Generate a key pair (private/public)
  2. Call the Reveal a Secret API passing over the public key, where the API will use the public key to encrypt the secret and return the secret_jwe value
  3. Use the matching private key to decrypt the secret_jwe value

To do this you will need a library for your programming language of choice that can manage keys, JWK/JWE and encryption with RSA.

The following is a Python example to perform all three steps above (thanks to my colleague Rajesh Kumar for the code).

It starts by generating a Key ID, then creating a key with Key Type of RSA, size of 2048 and the Key ID. A public key for this is exported. This is a JSON Web Key formatted object (example shown below).

The next section builds the API URL, sets the payload to be the “public_key” and then POSTs the request. See the Reveal a Secret documentation for more information. If successful (status_code = 200) it returns the fully serialized JWE in the secret_jwe field (example shown below).

The last section will use the private key to decrypt/decode the secret.

This concludes the exploration of the create/update and reveal operations.

Conclusion

Okta Privileged Access provides a generic secrets capability in it’s vault. Secrets, and the folders for storing them, can be managed via the web user interface, the client or via the Secrets API. This article has explored the different APIs available to manage folders and secrets. It has dived into the secret create, update and reveal operations and the needs of key management and JWE encryption to work with those APIs.

2 thoughts on “Using the Secrets API with Okta Privileged Access

Leave a Reply