Implementing an Offline Password Vault with Okta Privileged Access and KeePassXC

Okta Privileged Access is a SaaS offering. Currently it does not have an offline mode for local storage of break glass credentials. But you can extend it to do so, and that’s the subject of this article. We look at a simple mechanism to export secrets from a folder and push them into a local vault (in this case KeePassXC, an open source password manager). The article will provide an overview of the solution, dive into the mechanics of the components for those interested in building something similar, then discuss some of the security implications of this type of solution.

Introduction

Okta Privileged Access (OPA) can be used in many privileged access management scenarios, including storing break glass accounts and their credentials. These accounts can be stored in Secrets in OPA, and then policy applied to control who can access them and how – such as requiring MFA to access. Okta Identity Governance can be layered over it so that access to secrets can be transient and auditable.

OPA is a Software-as-a-Service implementation built on Okta’s cell architecture and subject to 99.99% SLA. But what if your internet connectivity is down and you need to access break glass accounts stored in OPA? Currently there is no offline mode for OPA, but there’s no reason you couldn’t implement your own.

This article will walk through a simple implementation of an offline mode to store break glass accounts in a local password vault. For this example we have chosen the open source KeePassXC as the local vault. The solution components are shown in the following figure.

Okta Privileged Access has it’s Vault with secrets stored in folders. It also has the usual collection of users, groups, admin roles, resource groups/projects and policies/rules.

The “local” components are stored on an Ubuntu Desktop machine. This machine has the OPA Client (sft) with a user enrolled on the machine who has permissions in OPA to access secrets (in specific folders).

The local machine also has KeePassXC installed, which includes the command line interface (keepassxc-cli), a database for the break glass passwords (entries) and the UI for accessing the passwords.

Finally, there is a custom script to use the sft client to get the relevant secrets and add/update them in the KeePassXC database. As you will see in the following sections, this is all very straightforward (but has some limitations).

This is a one-way solution – the secrets are pulled from the OPA Vault and written into the KeePassXC DB. It will add/update items in KeePassXC, but not delete them.

This solution only works on credentials stored as Secrets in the OPA Vault. It will not work on server shared accounts or SaaS Service Accounts as there is no way to reveal these credentials via the OPA client (or API). This means it’s ideally suited to only the break glass accounts – the “I’ve got no other option, I need to get at the account that will get me into the system to fix things” option.

Implementation

This section will drill into the details of the implementation.

KeePassXC

The most up-to-date version of KeePassXC was installed on the Ubuntu desktop. Note that the Ubuntu 22.04 instance we used had some challenges with self-signed certs with the default installation mechanisms. In the end we used “sudo apt install keepassxc”.

We created a local key file and a new database (BreakGlass.kdbx) using command line tools. This means that the database could be accessed using the local key file and not a password, making it easier to use in a script.

openssl rand -out keepass.keyx 256
keepassxc-cli db-create --set-key-file keepass.keyx Passwords.kdbx
keepassxc-cli db-info Passwords.kdbx --key-file keepass.keyx --no-password

Then to access the database via the UI, the key file is used instead of a password.

Within KeePass there is a single folder called Passwords. You could have multiple folders and have different names, but this was the default when the database was created and the export script is coded to work with a single folder.

Secrets in Okta Privileged Access

In OPA, a single top-level folder was created in it’s own Resource Group and Project. The single top-level folder was chosen for simplicity. You could have a hierarchy of folders for the break glass accounts, but the export script was written to process a single folder.

The single folder has a number of break glass accounts in it.

Each secret has three values: username, password and url. The export script will look for those three key names.

The URL is not strictly necessary, but KeePassXC has the ability to use the URL to connect to it with the credentials, so it’s included to show it getting added to the DB.

The Export Script

A simple Bash script was written to pull the secrets from the OPA folder and write (add or update) into the KeePassXC DB.

The script is just a simple example of how it could be done and we expect there are much better ways to script it. Consider it as a way to show the commands needed to pull secrets from OPA and write them into KeePassXC.

The high-level flow is:

  1. A set of variables are defined for the OPA Resource Group, Project and Folder where the secrets are stored.
  2. The OPA Client (sft) is used to get all secrets in the folder and write them to a temporary file
  3. Each secret in the file (each on a line) is processed in a function that will
    • Extract the secret ID and name from the line
    • Use the sft client to get the key:value pairs from the secret and store the username, password and url
    • Check to see if there’s already an entry in the KeePassXC DB for that secret and set the verb accordingly (“add” or “edit”). We could have put the next CLI command in the loop.
    • Use the KeePassXC CLI to add/update the password entry in the DB
  4. The temporary files are deleted

We will explore the different CLI commands used in the following sections.

Using the OPA Client to get the Secrets

The OPA client, sft, is a command line utility, often used for command-line connections to servers. However with the secrets capability added to OPA, a number of sft secrets options were added.

The export script uses two of these – one to list all secrets in a folder and one to reveal the key:value pairs of a secret.

These are restricted commands so will prompt the person executing the script to authenticate to Okta/OPA. If MFA is assigned to the OPA app, they will also need to respond to the MFA prompts. The user will only need to authenticate once. As there is no unattended mode (to be addressed with NHI work this year) the script must be run by a user authorized to access the secret folder and reveal the secrets.

The first call uses the sft secrets list command telling it what the resource group, project and folder id are.

sft secrets list --id $bg_id --resource-group $bg_rg --project $bg_pr | grep -v '^NAME' > ./temp_secrets.txt

The result is a tabular display with a header row. The command above removes that header and writes the output to a temporary file. The output of this command looks like the following, showing name, the secret id, RG & Project, and description.

TestBG1 key_value_secret 5aa64709-62dc-4eab-b728-a293965d5a03 BreakGlass_Secrets_RG BreakGlass_Secrets_Proj Test BreakGlass Account 1
AnotherBG key_value_secret 79d4deb6-996b-4742-aee4-71212f3c4379 BreakGlass_Secrets_RG BreakGlass_Secrets_Proj Another break glass account
TestBG2 key_value_secret eabfcc85-360a-4477-95f7-62b0652b2bcd BreakGlass_Secrets_RG BreakGlass_Secrets_Proj Test BreakGlass Account 2

The script will strip out the name and secret id from the list and then use the sft secrets reveal command to get the key:value pairs.

sft secrets reveal --resource-group $bg_rg --project $bg_pr --id $secret_id > ./temp_secretvals.txt

This results in a tabular output with the key:value pairs.

KEY_NAME SECRET_VALUE
username testacct2
password Fred1234
url https://okta.com

The values from the secret and key:value pairs are stored in variables to use with the KeePassXC CLI.

Adding/Updating Passwords in KeePassXC

KeePassXC also has a command line interface that’s installed with the product, keepassxc-cli.

We saw earlier how it can be used to define databases. It can also be used to show, add and edit entries, which we use in the script.

As there’s no CLI to add/update in the one command, we need to check to see if the entry is there first, using the keepassxc-cli show command.

keepassxc-cli show -k keepass.keyx --no-password BreakGlass.kdbx $secret_name

Note that we’re using the key file with a –no-password option meaning the person running the script does not need to enter in the KeePassXC DB password for every execution of a CLI command.

If the entry (by name) is found a verb variable is set to “edit” (i.e. edit an existing entry) otherwise it is set to “add” (i.e. add a new entry).

Then a second cli command is run to add/edit the entry.

echo $secret_password | keepassxc-cli $keepass_verb -k keepass.keyx --no-password -u $secret_username --url $secret_url -p BreakGlass.kdbx $secret_name

The existing password from OPA needs to be piped into the cli command, otherwise it will prompt for it to be entered which is not what we want.

At the completion of the script, you can see the three secrets now showing in the Passwords folder in the KeePassXC DB.

Each entry is based off the secret name in OPA, with the username, URL and password stored. You could apply KeePassXC controls to restrict access to the entries. Note that there is a Notes field – it would be nice to copy the OPA secret description into this field, but there’s no argument to pass to the cli for this.

So that’s it, a simple script to export secrets from a folder in OPA and create/update entries in a KeePassXC database to use as an offline store of break glass accounts.

A Few Thoughts on Security

Break glass accounts will normally be static, high-privilege accounts needed to fix something when all other means have failed. They should be used only in exceptional circumstances and should be managed with the utmost care.

If you have reached this point of the article, you would have seen usernames and passwords displayed in the clear, and that is a concern for break glass accounts. The following are some thoughts about applying better controls.

First is the choice of implementation. By using the OPA client (sft) you will export secret values in the clear as that is how the sft secrets reveal command is delivered. Unfortunately when handing off between one command (like the sft command) and another (like the keepassxc-cli command) you will need to pass a password value. If it’s in a script, it may be visible. A better design would be to use compiled code with relevant API calls so passwords are better controlled.

This implementation is built on a single users workstation. It relies on an sft client being installed and enrolled for a specific user on a specific workstation. That user will also be tied to a group that controls the access to the secret folder and secrets. They will also need to authenticate to Okta/OPA when they run the script (preferably with MFA). So there are multiple layers of controls. If implementing a solution like this you should consider how widely you deploy it – ideally keeping it to one or two people that are highly trusted.

The Okta/OPA implementation has a separate top-level secrets folder in it’s own Resource Group and Project. This keeps it away from other secrets folders and users. You should apply delegated administration to this RG and minimise the users who can access. Similarly a separate Policy should be applied to a tightly controlled group of users (with governance controls wrapped around the group membership) who can access the secrets. MFA should be used.

In this example implementation, the script, key file and KeePassXC DB files are stored in a single directory on the users workstation. This directory should be hardened so only the authorized user can access it.

The script does use temporary files to store the list of secrets and then the key:value pairs for each one. This was done to keep the script simple. If implementing something based off this, you should think of a better (in-script/in-memory) way of processing the data extracted from OPA.

The keepassxc-cli commands are using a key file to reduce the need for the user to type in a password every time they run the script. This is a better approach than using passwords, but this file should be secured as effectively as the actual database.

Finally, this script has been written to run interactively by a user. The OPA client requires this as it will need to authenticate the user. It cannot run on a schedule in the background. When the NHI capabilities are added to OPA, it may be feasible to run this automatically in the background.

Conclusion

In this article we have presented an example of implementing an offline vault for storing break glass accounts, and a means to synchronise secrets from Okta Privileged Access into a local vault. The vault used is KeePassXC, an open source password manager that can run on many platforms. The article provided an overview of the mechanism then walked through how the components were implemented, how the OPA and KeePassXC CLIs were used in a script to copy secrets across and ended with some security considerations for a solution like this.

The article has shown that whilst there is no native offline vaulting capability in OPA, it’s very straightforward to implement one. If you’re concerned that OPA being a SaaS app and the internet may not be available, it provides a means to mitigate that risk.

Leave a Reply