Introduction

This is a one-time activity that will persist your credentials to your localhost until you delete them.

More information is available at https://ras44.github.io/blog/2019/01/19/keeping-credentials-secret-with-keyrings-in-r.html.

We often need to provide credentials to access resources such as databases. Hardcoding these credentials is frowned upon as it could lead to these credentials being exposed (e.g. committed to GitHub). To protect this information, we can store passwords, tokens, and other sensitive information in a keyring using the keyring library. The code presented below is available in GitHub at https://github.com/NACHC-CAD/r-keyring.

Store a value in a keyring

The following code shows the create_keyring function defined in the r-keyring project.

# ---
#
# function to create a keyring
#
# ---

# installs
# install.packages("keyring")

# libraries
library(keyring)

# create the key ring
create_keyring <- function(kr_name, kr_service, kr_username) {
  kb <- keyring::backend_file$new()
  kb$keyring_create(kr_name)
  kb$set(kr_service, username = kr_username, keyring = kr_name)
  kb$keyring_lock(kr_name)
}

When this code is call, you will be asked to enter a keyring password. This is the password that you use when you want to retrieve your password or token. In this example we use “foo”.

You will then be asked to enter a password.

This is the password or token for your database. In this example we entered “asdf1098743n12lkjj5-MY_TOKEN-aoipuoi19087mnoipuasddf”.

After you have stored your password/token in the keyring it can be fetched using the code below.
# get the password from the keyring
keyring::backend_file$new()$get(
  service = kr_service,
  user = kr_username,
  keyring = kr_name
)

When you execute this code you will be asked for the password for the keyring (in this example we used “foo”).

This code will output the following.
> # get the password from the keyring
> keyring::backend_file$new()$get(
+   service = kr_service,
+   user = kr_username,
+   keyring = kr_name
+ )
[1] "asdf1098743n12lkjj5-MY_TOKEN-aoipuoi19087mnoipuasddf"

We can then use something like the following to securely create a url to connect to Databricks.
#
# functions to get databricks token (user will be prompted for keyring password)
#

getToken <- function () {
  return (
    keyring::backend_file$new()$get(
      service = "databricks",
      user = "token",
      keyring = "databricks_keyring"
    )
  )
}

#
# functions to get databricks token (user will be prompted for keyring password)
#

getUrl <- function () {
  url <- "jdbc:databricks://nachc-databricks.cloud.databricks.com:443/default;transportMode=http;ssl=1;httpPath=sql/protocolv1/o/3956472157536757/0123-223459-leafy532;AuthMech=3;UseNativeQuery=1;UID=token;PWD="
  return (
    paste(url, getToken(), sep = "")
  )  
}

Putting it All Together

You should be able to run the code in the r-keyring project shown below as is to store your Databricks token. You will be asked to enter a password for the keyring and your Databricks token.

# ---
#
# example script to create/delete a keyring
#
# ---

# installs
# install.packages("keyring")

# libraries
library(keyring)

# source 
source("CreateKeyRing.R")
source("DeleteKeyRing.R")

# variables
kr_name <- "databricks_keyring"
kr_service <- "production"
kr_username <- "token"

kb <- keyring::backend_file$new()

# list existing keyrings (before)
kb$keyring_list()

# delete existing
delete_keyring(kr_name)
create_keyring(kr_name,kr_service,kr_username)

# list existing keyrings (after)
kb$keyring_list()

# get the token
keyring::backend_file$new()$get(
  service = kr_service,
  user = kr_username,
  keyring = kr_name
)

Optional: Only Create the Key Ring if it Does Not Exist

The code can be modified as shown below so that the key ring is only created if it does not exist.

createDatabaseKeyRing <- function(kr_name, kr_service, kr_username) {
  kb <- keyring::backend_file$new()
  # Get a list of existing keyrings
  existing_keyrings <- kb$keyring_list()
  # Check if the keyring already exists
  if (!(kr_name %in% existing_keyrings$keyring)) {
    kb$keyring_create(kr_name)
    kb$set(kr_service, username = kr_username, keyring = kr_name)
    kb$keyring_lock(kr_name)
  } else {
    print(paste("Keyring already exists for: ", kr_name))
  }
}