Author: Hong Ooi

# Introduction to AzureKeyVault

#### Hong Ooi

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

- Cryptographic keys: Supports multiple key types and algorithms, and enables the use of Hardware Security Modules (HSM) for high value keys.
- Secrets: Provides secure storage of secrets, such as passwords and database connection strings.
- Certificates: Supports certificates, which are built on top of keys and secrets and add an automated renewal feature.
- Azure Storage: Can manage keys of an Azure Storage account for you. Internally, Key Vault can list (sync) keys with an Azure Storage Account, and regenerate (rotate) the keys periodically.

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:

- `create`: Create a new key, or a new version of an existing key.
- `import`: Import a key from a PEM file.
- `get`: Retrieve an existing key.
- `list`: List all keys in the vault.
- `delete`: Delete a key.
- `backup`: Return a base64-encoded blob representing the key.
- `restore`: Use a blob obtained by the `backup` method to restore a key.
- `do_operation`: Carry out arbitrary REST operations on keys. Used by the above methods.

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

- `list_versions`: List the available versions for this key.
- `set_version`: Set the version of the key to use. The default is to use the most recently created version.
- `encrypt`: Encrypt a character string or raw vector, producing a base64-encoded ciphertext string.
- `decrypt`: Decrypt a ciphertext string, producing either a character string or raw vector. The inverse operation of `encrypt`.
- `sign`: Sign a hashed digest.
- `verify`: Verify the signature of a hash. The inverse operation of `sign`.
- `wrap`: Wrap a symmetric key. This is technically the same as encrypting it, but is provided as a distinct operation to allow more granular management of permissions.
- `unwrap`: Unwrap a wrapped key. The inverse operation of `wrap`.

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:

- `create`: Create a new secret, or a new version of an existing secret.
- `get`: Retrieve an existing secret.
- `list`: List all secrets in the vault.
- `delete`: Delete a secret.
- `backup`: Return a base64-encoded blob representing the secret.
- `restore`: Use a blob obtained by the `backup` method to restore a secret.
- `do_operation`: Carry out arbitrary REST operations on secrets. Used by the above methods.

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:

- `list_versions`: List the available versions for this secret.
- `set_version`: Set the version of the secret to use. The default is to use the most recently created version.

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:

- `create`: Create a new certificate, or a new version of an existing certificate. The default is to create a self-signed certificate.
- `import`: Import a certificate from a PFX file.
- `get`: Retrieve an existing certificate.
- `list`: List all certificates in the vault.
- `delete`: Delete a certificate.
- `backup`: Return a base64-encoded blob representing the certificate.
- `restore`: Use a blob obtained by the `backup` method to restore a certificate.
- `set_contacts`: Set the email address(es) to contact when a certificate is due for renewal.
- `get_contacts`: Get the email address(es) of the contacts.
- `add_issuer`: Adds the details for an issuer (certificate authority).
- `get_issuer`: Retrieve the details for an issuer.
- `remove_issuer`: Removes the details for an issuer.
- `list_issuers`: Lists the issuers available to this vault.
- `do_operation`: Carry out arbitrary REST operations on certificates. Used by the above methods.

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

- `list_versions`: List the available versions for this certificate.
- `set_version`: Set the version of the certificate to use. The default is to use the most recently created version.
- `export`: Export the certificate as either a PEM or PFX file (the format is fixed at certificate creation).
- `export_cer`: Export the certificate public key as a CER file.
- `sign`: Sign a hashed digest.
- `verify`: Verify a signature against a digest.
- `set_policy`: Sets the policy for a certificate, ie the authentication details.
- `get_policy`: Retrieve the policy for a certificate.

    # 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:

- `add`: Add a new storage account.
- `get`: Retrieve an existing account.
- `list`: List all storage accounts in the vault.
- `remove`: Stop managing a storage account.
- `backup`: Return a base64-encoded blob representing the storage account.
- `restore`: Use a blob obtained by the `backup` method to restore an account.
- `do_operation`: Carry out arbitrary REST operations on accounts. Used by the above methods.

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.

- `regenerate_key`: Manually regenerate an access key.
- `create_sas_definition`: Create a SAS definition, from which an actual SAS can be obtained.
- `get_sas_definition`: Retrieve an existing SAS definition.
- `delete_sas_definition`: Delete a SAS definition.
- `list_sas_definitions`: List existing SAS definitions.
- `show_sas`: Get a SAS from a definition.

    # 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.