Introduction to AzureKeyVault

Hong Ooi

Azure Key Vault enables Microsoft Azure applications and users to store and use several types of secret/key data:

AzureKeyVault is an R package for working with the Key Vault service. It provides both a client interface, to access the contents of the vault, and a Resource Manager interface for administering the Key Vault itself.

Resource Manager interface

AzureKeyVault extends the AzureRMR package to handle key vaults. In addition to creating and deleting vaults, it provides methods to manage access policies for user and service principals.

# create a key vault
rg <- AzureRMR::get_azure_login()$
    get_subscription("sub_id")$
    get_resource_group("rgname")
kv <- rg$create_key_vault("mykeyvault")

# list current principals (by default includes logged-in user)
kv$list_principals()

# get details for a service principal
svc <- AzureGraph::get_graph_login()$
    get_service_principal("app_id")

# give the service principal read-only access to vault keys and secrets
kv$add_principal(svc,
    key_permissions=c("get", "list", "backup"),
    secret_permissions=c("get", "list", "backup"),
    certificate_permissions=NULL,
    storage_permissions=NULL)

Client interface

The client interface is R6-based. To instantiate a new client object, call the key_vault function. This object includes sub-objects for interacting with keys, secrets, certificates and managed storage accounts.

vault <- key_vault("https://mykeyvault.vault.azure.net")

# can also be done from the ARM resource object
vault <- kv$get_endpoint()

Keys

Key Vault supports RSA and elliptic curve (ECDSA) asymmetric encryption keys. The keys component of the client object provides methods for managing keys:

In turn, an individual key is represented by an object of class stored_key. This has the following methods:

The key object contains the public key component in the key field, as a parsed JSON web key. Note that Azure Key Vault does not provide access to the private key component.

# create a new RSA key with 4096-bit key size
vault$keys$create("newkey", type="RSA", rsa_key_size=4096)

key <- vault$keys$get("newkey")

# encrypting and decrypting
plaintext <- "super secret"
ciphertext <- key$encrypt(plaintext)
decrypted_text <- key$decrypt(ciphertext, as_raw=FALSE)
plaintext == decrypted_text
#> [1] TRUE

# signing and verifying
dig <- openssl::sha256(charToRaw(plaintext))
sig <- key$sign(dig)
key$verify(sig, dig)
#> [1] TRUE

# exporting the public key component, using the jose and openssl packages
pubkey <- key$key
openssl::write_pem(jose::read_jwk(pubkey), "pubkey.pem")

# importing a key generated by openssl
sslkey <- openssl::rsa_keygen()
vault$keys$import("sslkey", sslkey)

# importing a key from a file
openssl::write_pem(sslkey, "sslkey.pem")
vault$keys$import("sslkeyfromfile", "sslkey.pem")

Secrets

Key Vault allows you to store confidential information such as passwords, database connection strings, tokens, API keys, and so on. The secrets component of the client object provides methods for managing generic secrets:

An individual secret is represented by an object of class stored_secret. Unlike a key, a secret is essentially just data, so the object does not provide any operations. It has the following methods for managing secret versions:

The secret itself is in the value field of the object, of class secret_value. This class has a print method that hides the value, to help guard against shoulder-surfing. Note that this will not stop a determined attacker; as a general rule, you should minimise assigning secrets or passing them around your R environment. If you want the raw string value itself, eg when passing it to jsonlite::toJSON or other functions which do not accept arbitrary object classes as inputs, use unclass to strip the class attribute first.

# create a new secret
vault$secrets$create("newsecret", "hidden text")
secret <- vault$secrets$get("newsecret")
secret$value
#> <hidden>

Certificates

The certificates component provides methods for working with SSL/TLS authentication certificates:

An individual certificate is represented by an object of class stored_certificate. This has the following methods:

# create a new self-signed certificate (will also create an associated key and secret)
cert <- vault$certificates$create("newcert",
    subject="CN=example.com",
    x509=cert_x509_properties(dns_names="example.com"))

# import a certificate from a PFX file
vault$certificates$import("importedcert", "mycert.pfx")

# export the certificate as a PEM file
cert$export("newcert.pem")

# to export as a PFX file, set the 'format' argument at cert creation
newcert2 <- vault$certificates$create("newcert2",
    subject="CN=example.com",
    format="pfx")
newcert2$export("newcert2.pfx")

Note that exporting a certificate to a file should not be done unless absolutely necessary, as the point of using Key Vault is to avoid having to save sensitive data on a local machine.

The AzureAuth package is able to make use of certificates stored in Key Vault to authenticate with Azure Active Directory. Here is some example code to do so. The app (client) in question needs to be setup with the certificate public key; we create the app via the AzureGraph package and pass it the key.

## create a registered app in Azure Active Directory with cert credentials
gr <- AzureGraph::get_graph_login()
certapp <- gr$create_app("certapp", password=FALSE, certificate=cert$cer)

# authenticate using data in Key Vault
AzureAuth::get_azure_token("resource_url", "mytenant", certapp$properties$appId,
    certificate=cert)

Storage accounts

Key Vault can be configured to manage access to an Azure Storage Account, by automatically regenerating access keys and saving commonly-used access patterns as shared access signature (SAS) templates. The storage component of the client object provides methods for working with managed accounts:

An individual certificate is represented by an object of class stored_account, which has the following methods. Note that unlike the other types of objects, storage accounts are not versioned.

# get the storage account details
library(AzureStor)
res <- AzureRMR::get_azure_login()$
    get_subscription("sub_id")$
    get_resource_group("rgname")$
    get_storage_account("mystorageacct")

# add a managed storage account
stor <- vault$storage$add("mystorage", res, "key1")

# Creating a new SAS definition
today <- Sys.time()
sasdef <- res$get_account_sas(expiry=today + 7*24*60*60, services="b", permissions="rw")
stor$create_sas_definition("newsas", sasdef, validity_period="P15D")

stor$show_sas("newsas")

See also

For more information, see the official Key Vault documentation.