WL#9770: Keyring plugin for Oracle Public Cloud key store
Affects: Server-8.0
—
Status: Complete
Implement a MySQL keyring plugin talking to an Oracle Public Cloud's Key management service (Now known as Oracle Cloud Infrastructure Vault, OCI Vault) (1) back-end. https://docs.cloud.oracle.com/iaas/Content/KeyManagement/Concepts/keyoverview.htm MySQL provides keyring plugins for both the OKV and the competing AWS KMS. The OCI Vault is a natural fit for these secrets. So this plugin is a recommended addon for MySQL OCI instances. It can work on premise too. And be a great gateway to OCI. Standalone hardware key servers can be expensive. If you trust OCI with your keys, then the OCI can be a great substitute for the expensive on-premise hardware appliance.
FR1 - KEY STORAGE All keys are to be stored in, and retrieved from the Oracle's Cloud Infrastructure Vault service (OCI Vault). FR2 - ENTITY MAPPING MySQL keys are uniquely mapped to the OCI Vault internal secrets. FR3 - CONSUMER SUPPORT Backend is to support all of the MySQL server keyring consumers. FR4 - AUTHENTICATION The plugin will use the provided user's credentials. FR5 - PLUGIN CONFIGURATION The plugin will support the following configuration parameters coming from persistent system variables: FR5.1 - User OCID of the OCI user. FR5.2 - Tenancy OCID of the OCI tenancy. FR5.3 - Compartment OCID of the MySQL sub-compartment. FR5.4 - Vault OCID of the OCI Vault the MySQL will use. FR5.5 - OCI encryption endpoint URL FR5.6 - OCI Key Management endpoint URL FR5.7 - OCI Vault endpoint URL FR5.8 - OCI Secrets endpoint URL FR5.9 - Key OCID of the master encryption key used for secrets encryption FR5.10 - API user private key file location FR5.11 - API user private key fingerprint FR5.12 - Certificate file location for HTTPS connection verification. Optional. FR6 - CONFIGURATION UPDATE No live configuration update will be provided for this keyring. Server restart will be necessary for changing the configuration. FR7 - MIGRATION SUPPORT The plugin will support key migration service both as a source and a destination. The common keyring migration requirements apply. FR8 - SINGLE SERVER PER OCI COMPARTMENT Dedicated OCI compartment is recommended for every instance of the MySQL server. FR9 - PERFORMANCE SCHEMA performance_schema.keyring_keys FR10 - UDF Fully support the keyring_udf keyring functions provided. FR11 - SETUP HELPER Provide means to ease the creation of OCI compartments, vaults, obtaining their OCIDs and all the necessary requirements for this plugin. FR12 - SUPPORTED KEY TYPES Provide support for all of the OCI Vault supported key types.
The plugin is to be implemented as a part of MySQL keyring infrastructure. FR1 - KEY STORAGE All the keys are stored in OCI Vault secure secret storage system. None of the key information is to be permanently stored at MySQL server local storage. Only the list of the key IDs is stored in the server's memory cache, the key data is retrieved from the server every time it is requested. Random key generation is performed on the OCI Vault Key Management system, and the keys are subsequently stored on to the OCI Vault server. FR2 - ENTITY MAPPING MySQL keys are uniquely identified by a set of information: 1. User ID 2. ID 3. Type (cipher) 4. Value For internal key users, the User ID is not available. Keys are uniquely mapped to OCI Vault secrets identifiers in the form of: https://vaults.us-ashburn- 1.oci.oraclecloud.com/20180608/secrets/ocid1.vaultsecret.oc1.iad.abaaaaaaa6iduka awfj624xscisqs6eix24d7k4mvt42mmdegxs36ck46a7a where "https://vaults.us-ashburn-1.oci.oraclecloud.com" is path to the provided OCI Vault server, while the "ocid1.vaultsecret.oc1.iad.abaaaaaaa6idukaawfj624xscisqs6eix24d7k4mvt42mmdegxs36 ck46a7a" is the internal OCID of the key stored in the Vault. The 20180608 is the API version as specified in the REST API documentation at https://docs.cloud.oracle.com/en- us/iaas/api/#/en/key/release/ The MySQL plugin will authenticate against the OCI Vault using the SSH key and fingerprint scheme described at https://docs.cloud.oracle.com/en- us/iaas/Content/API/Concepts/apisigningkey.htm . The MySQL keyring_OCI plugin won't store keys with missing ID or Value. The OCI Vault supports storing existing key data (in a secret) in any format. The maximum allowable size for a secret bundle is 25 KB. https://docs.cloud.oracle.com/en- us/iaas/Content/KeyManagement/Tasks/managingsecrets.htm The OCI Vault supports generating key of type AES, of length 16, 24, or 32 bytes. https://docs.cloud.oracle.com/en- us/iaas/api/#/en/key/release/datatypes/KeyShape * Note: the documentation states that RSA keys are also supported, but the OCI KMS team confirmed that RSA keys will not be supported. Only AES keys can be generated. FR3 - CONSUMER SUPPORT MySQL services/features depending on keyring infrastructure should be able to access and use keyring services backed by plugin. These include: - InnoDB consumer - Audit log consumer - Keyring UDF consumer - Performance Schema keyring_keys table - binlog encryption FR4 - OCI VAULT AUTHENTICATION MySQL server will be able to authenticate against OCI Vault tenancy by using an application user and private key that is registered to the API user in the OCI. As a precaution, the key's fingerprint is used too. The Keyring_OCI plugin will permanently store the SSH key and fingerprint in memory and use them to connect to the OCI Vault backend. The provided credentials are expected to remain valid indefinitely. The Application authentication scheme is documented here: https://docs.cloud.oracle.com/en- us/iaas/Content/API/Concepts/signingrequests.htm FR5 - PLUGIN CONFIGURATION Plugin will support configuration settings stored in persistent system variables. FR5.1 - User OCID of the OCI user. It is necessary to have the Vault feature enabled for this user. How to obtain the OCID: https://docs.cloud.oracle.com/en- us/iaas/Content/API/Concepts/apisigningkey.htm#five * Variable Name: keyring_oci_user * Variable Type: string * Description: The OCI User ocid used for connection to the cloud. * Type: Global * Settable at runtime: No * Default: NONE FR5.2 - Tenancy OCID of the OCI tenancy. How to obtain the OCID: https://docs.cloud.oracle.com/en- us/iaas/Content/General/Concepts/identifiers.htm#two * Variable Name: keyring_oci_tenancy * Variable Type: string * Description: The OCI Tenancy ocid where the MySQL compartment resides. * Type: Global * Settable at runtime: No * Default: NONE FR5.3 - Compartment OCID of the MySQL sub-compartment. Create a MySQL (sub)compartment in the tenancy. Obtain the compartment ID. Note: Make sure there are no existing Vault Keys or Vault Secrets in this compartment and this compartment is not used by other systems than MySQL server keyring plugin. How to manage compartments and obtain the OCID: https://docs.cloud.oracle.com/en- us/iaas/Content/Identity/Tasks/managingcompartments.htm * Variable Name: keyring_oci_compartment * Variable Type: string * Description: The OCI compartment ocid within the tenancy where the MySQL keys reside. * Type: Global * Settable at runtime: No * Default: NONE FR5.4 - Vault OCID of the OCI Vault the MySQL will use. Create a new Virtual Vault in the MySQL compartment. Obtain the vault OCID. Note: You can reuse an existing vault that is in a parent compartment of the MySQL sub-compartment. Each compartment users can see and use only the keys in their respective compartment. Vault documentation how to create a virtual vault and obtain the vault OCID: https://docs.cloud.oracle.com/en- us/iaas/Content/KeyManagement/Tasks/managingvaults.htm * Variable Name: keyring_oci_virtual_vault * Variable Type: string * Description: The OCI Virtual Vault ocid used for all the encryption operations. * Type: Global * Settable at runtime: No * Default: NONE FR5.5 - OCI encryption endpoint URLs In the Vault details page, copy the OCID, Cryptographic and Management endpoints. The Encryption endpoint is used for generating ciphertext for new keys. It has the form of <>-crypto.kms.us-ashburn-1.oraclecloud.com where xyz is the middle part of the Virtual Vault OCID. * Variable Name: keyring_oci_encryption_endpoint * Variable Type: string * Description: The OCI encryption server endpoint. * Type: Global * Settable at runtime: No * Default: NONE FR5.6 - OCI Key Management endpoint URL The Key Management endpoint is used for listing the existing keys. It has the form of < >-management.kms.us-ashburn-1.oraclecloud.com where xyz is the middle part of the Virtual Vault OCID. * Variable Name: keyring_oci_management_endpoint * Variable Type: string * Description: The OCI key management server endpoint. * Type: Global * Settable at runtime: No * Default: NONE FR5.7 - OCI Vault endpoint URL The Vaults endpoint is used for obtaining the value of secrets. It has the form of vaults.us-ashburn-1.oci.oraclecloud.com * Variable Name: keyring_oci_vaults_endpoint * Variable Type: string * Description: The OCI vaults server endpoint. * Type: Global * Settable at runtime: No * Default: NONE * Example: vaults.us-ashburn-1.oci.oraclecloud.com FR5.8 - OCI Secrets endpoint URL The Secrets endpoint is used for listing, creating and retiring of secrets. It has the form of secrets.< > * Variable Name: keyring_oci_secrets_endpoint * Variable Type: string * Description: The OCI vaults server endpoint. * Type: Global * Settable at runtime: No * Default: NONE * Example: "secrets." + 5.7 OCI Vault endpoint URL (e.g. "secrets.vaults.us- ashburn-1.oci.oraclecloud.com") FR5.9 - Key OCID of the master encryption key used for secrets encryption The keyring plugin requires existing cryptographic key in the OCI compartment to be used for secret's encryption. How to create a key: https://docs.cloud.oracle.com/en- us/iaas/Content/KeyManagement/Tasks/managingkeys.htm Provide a MySQL-specific name for the generated key, and do not use it for other purposes. * Variable Name: keyring_oci_master_key * Variable Type: string * Description: The OCI encryption key ocid used for all the secret's encryption. * Type: Global * Settable at runtime: No * Default: NONE FR5.10 - API user private key file location Upload the public key in the user control panel. How to create and upload an API key: https://docs.cloud.oracle.com/en- us/iaas/Content/API/Concepts/apisigningkey.htm#two * Variable Name: keyring_oci_key_file * Variable Type: string * Description: The file path to the RSA private key used for OCI authentication. * Type: Global * Settable at runtime: No * Default: NONE FR5.11 - API user public key fingerprint The key fingerprint can be obtained while creating the API keys, by running openssl rsa -pubout -outform DER -in ~/.oci/oci_api_key.pem | openssl md5 -c or from the user's control panel: https://docs.cloud.oracle.com/en- us/iaas/Content/API/Concepts/apisigningkey.htm#How3 * Variable Name: keyring_oci_key_fingerprint * Variable Type: string * Description: The RSA private key's fingerprint used for OCI authentication. * Type: Global * Settable at runtime: No * Default: NONE FR5.12 - Path to Certificate Authority (CA) bundle. Optional path to a file holding one or more certificates to verify the peer with. If it is not provided, the default CA bundle installed in the system will be used for certificate verification. If it is set to 'disabled' (without quotes), CURLOPT_SSL_VERIFYPEER = 0 will be used and no certification verification will be done. See https://curl.haxx.se/libcurl/c/CURLOPT_CAINFO.html for more details. * Variable Name: keyring_oci_ca_certificate * Variable Type: string * Description: CA certificate bundle file path used for OCI's certificate verification. * Type: Global * Settable at runtime: No * Default: "" - use default system certificate bundle for verification FR6 - CONFIGURATION UPDATE The users will not be able to update the plugin configuration of a running plugin. The settings can be changed only offline. FR7 - MIGRATION SUPPORT Plugin will support key migration service as a source and a target. Plugin configuration in migration mode is configured as described in FR6. FR8 - SINGLE SERVER PER OCI COMPARTMENT The plugin requires a dedicated OCI compartment within the user's tenancy for every instance of the MySQL server. Sharing the tenancy, while technically possible, can lead to concurrency issues. That's why only one server should be allowed to modify the keys and secrets. It is possible to have other MySQL servers' keyring_oci plugins to connect to the same tenancy and reuse the existing secrets. FR9 - PERFORMANCE SCHEMA The performance_schema.keyring_keys table is used to query the list of the keys known to the active keyring plugins. For the backends that support it, displays the backend OCID of the stored keys. In the case of the keyring_oci this will be the secret ocid. FR10 - UDF Fully support the keyring_udf keyring functions provided in a similar fashion to the other keyring plugins FR11 - SETUP HELPER Setting up the keyring OCI plugin requires setting lots of variables - see FR.5. This limits the usability and creates a steep learning curve how to use this keyring plugin. And many of the OCI customers are not experts in cloud, they have just an username, password and entry point to the cloud. In order to help customers that don't have the whole environment set up, an interactive script will guide the user through the process of buying OCI subscription (if they don't have one yet), obtaining the datacenter region ("us-ashburn-1" for example), the provided user's (FR5.1) and tenancy (FR5.2) OCIDs, and then guide the user how to generate (or generate one for the user automatically) an RSA private key (FR5.10 and FR5.11) Then the script will guide the user how to upload this key to the OCI. Unfortunately, until the private key is uploaded, no script can access the OCI so these steps must be done manually by the user. Having the datacenter region, the user and tenancy OCID, the script can connect to the cloud and generate the next items necessary for the keyring plugin: * compartment within the tenancy (FR5.3). It is not necessary but highly recommended that each activity in the tenancy happens in a separate compartment. This creates a level of abstraction and isolation. * Virtual Vault (FR5.4). Of course the user must have bought a subscription that allows Vault usage. * Having the vault OCID the script can obtain the suffix that is used for the key and encryption endpoints. "bbo6pux3aacuu" in my case. FR5.5 and FR5.6 * The vault and secrets endpoint are just "vaults."/"secrets." sub- domains of the datacenter region ("us-ashburn-1.oci.oraclecloud.com" for example). FR5.7 and FR5.8 * Having the virtual vault created and setup, the script can use it to create the master encryption key FR5.9 FR12 - SUPPORTED KEY TYPES Provide support for all of the OCI Vault supported key types. Currently the OCI Vault supports generating key of type RSA and AES, of length 16, 24, or 32 bytes. https://docs.cloud.oracle.com/en- us/iaas/api/#/en/key/release/datatypes/KeyShape --- Key Management workflow with Oracle Cloud Vault --- 1. Master Encryption Key All the secrets, stored in the OCI Vault, need to be encrypted with an OCI key. Such key will be created by the install script and will be provided as an system variable to the keyring_oci plugin by FR5.9 2. Storing existing customer encryption key MySQL keyring plugins support storing existing customer keys in the keyring. Such encryption keys will be stored as a "secret" in the OCI Vault. Since the 2020 March update, the OCI supports storing customer data in the Vault (previously known as KMS, Key Server) POST https://vaults.us-ashburn-1.oci.oraclecloud.com/20180608/secrets { "vaultId": "ocid1.vault.oc1.iad.bbo6pux3aacuu.abuwcljrjuje2hb2dyc2hkfol6rxukzjdy43bayoklz7m wszjhstpcwzodhq", "compartmentId": "ocid1.compartment.oc1..aaaaaaaalas4ioucpe3o3a764cqgwmothsbxmuxkhwq2klz6vrilnx67 ftdq", "secretName": "< >", "keyId": "ocid1.key.oc1.iad.bbo6pux3aacuu.abuwcljsguqx3mhymmxs44l65dp5zc5seg6yctjwsiemg4q zuwidlhn5s2ia", "secretContent": { "content": "aGVsbG8h", "contentType": "BASE64" }, "freeformTags": { "user": "< >", "type": "< >", "source": "< >" } } Where the secretName is the ID of the existing key, and secretContent.Content is the Base64 value of the existing key's data. Here, and in all subsequent requests, the keyId is the OCID of the Master Encryption Key above. 3. Creating a new encryption key The OCI vault supports creating encryption key data: POST https://bbo6pux3aacuu-crypto.kms.us-ashburn- 1.oraclecloud.com/20180608/generateDataEncryptionKey { "includePlaintextKey": true, "keyId": "ocid1.key.oc1.iad.bbo6pux3aacuu.abuwcljsguqx3mhymmxs44l65dp5zc5seg6yctjwsiemg4q zuwidlhn5s2ia", "keyShape": { "algorithm": "< >", "length": < > } } Where the server is the crypto endpoint of the OCI Vault Here is a sample response from the Vault: { "ciphertext": "IXcdmdJdcT3qAJVuL7MWawPKolMHa39uE6JEDYCmaofGQky3tBC5gwPzKk88PFdiD0oqGAMhAAAAAA= =", "plaintext": "4ptRNgEEctssPnaf23guow==", "plaintextChecksum": "3212534271" } Where the plaintext contains the Base64 encoded encryption key's data. This newly generated key must be stored in the Key Vault as described in the previous point. Since it is a two-step process, the storing step may fail. As a result, the generated ciphertext will be lost. But no object is created on the OCI so nothing will be left dangling. Consecutive creations of a new key will generate new ciphertext. 4. Enumerating the encryption keys stored in the OCI Vault GET https://vaults.us-ashburn-1.oci.oraclecloud.com/20180608/secrets? compartmentId=ocid1.compartment.oc1..aaaaaaaap2jegooilnqf2wokm2n4bb2qvh4vcmuntwp me4fsrbn77n5ft7bq As described in point.2, the key ID is stored in the "secretName" field. The keyId is the internal OCID used for extracting the key data or deleting the key. Here is an example response from the OCI: { "compartmentId": "ocid1.compartment.oc1..aaaaaaaap2jegooilnqf2wokm2n4bb2qvh4vcmuntwpme4fsrbn77n5f t7bq", "definedTags": { "Oracle-Tags": { "CreatedBy": "iroylev", "CreatedOn": "2020-05-22T11:13:26.827Z" } }, "description": null, "freeformTags": { "source": "generated", "type": "AES", "user": "root@localhost" }, "keyId": "ocid1.key.oc1.iad.bbo6pux3aacuu.abuwcljsguqx3mhymmxs44l65dp5zc5seg6yctjwsiemg4q zuwidlhn5s2ia", "id": "ocid1.vaultsecret.oc1.iad.amaaaaaas6idukaama27b4cvb3dxytlwi2l5shp5iu4p5o3wxjt63 rzlsudq", "lifecycleDetails": null, "lifecycleState": "ACTIVE", "rotationDetails": null, "secretName": "MyKey_256", "timeCreated": "2020-05-22T11:13:26.710Z", "timeOfCurrentVersionExpiry": null, "timeOfDeletion": null, "vaultId": "ocid1.vault.oc1.iad.bbo6pux3aacuu.abuwcljrjuje2hb2dyc2hkfol6rxukzjdy43bayoklz7m wszjhstpcwzodhq" } Here only keys that have "lifecycleState": "ACTIVE" are taken into account. Also, keys that are missing the freeformed tags "source", "type" and "user" are ignored. Only valid sources are generated and uploaded. 5. Extracting the encryption key from the OCI Vault GET https://secrets.vaults.us-ashburn- 1.oci.oraclecloud.com/20190301/secretbundles/ocid1.vaultsecret.oc1.iad.amaaaaaas 6idukaawfj624xscisqs6eix24d7k4mvt42mmdegxs36ck46a7a Here is an example response from the OCI: { "secretId": "ocid1.vaultsecret.oc1.iad.amaaaaaas6idukaawfj624xscisqs6eix24d7k4mvt42mmdegxs36 ck46a7a", "timeCreated": "2020-04-15T14:29:59.452Z", "versionNumber": 1, "versionName": null, "secretBundleContent": { "contentType": "BASE64", "content": "d2hhdGV2ZXI=" }, "timeOfDeletion": null, "timeOfExpiry": null, "stages": [ "CURRENT", "LATEST" ], "metadata": null } Where the secretBundleContent.content is the Base64 encoded encryption key's data to be used by the keyring plugin. 6. Deleting an existing key. POST https://bbo6pux3aacuu-management.kms.us-ashburn- 1.oraclecloud.com/20180608/keys/ocid1.key.oc1.iad.bbo6pux3aacuu.abuwcljshlr7gsbl jdvbn73dnazqxxpprzqo2ysut4xt5qqfmww7mjhmrexq/actions/scheduleDeletion with an empty body {} Here the internal OCID of the secret is used (not the customer-facing key id). Note that the OCI Vault does not instantly delete any keys or secrets. It just schedules them for deletion, marking their "lifecycleState": "PENDING_DELETION". After a grace period (one month) they will be deleted. By then such keys cannot be used for encryption and their secret data cannot be obtained. The keyring_oci plugin ignores keys marked for pending deletion.
The OCI Vault provides HTTP API based on POST requests. The following functionality will be used in the plugin: 1. Query builder and parser. The REST API for accessing the OCI infrastructure is described in https://docs.cloud.oracle.com/iaas/Content/API/Concepts/usingapi.htm RapidJSON library will be used to prepare the request body and parse the request response. The Request class from request.h will handle the request preparation and execution. This class is template specialized for the GET and POST operations. The Request_headers class from request_headers.h will handle the request headers preparation and signature. This class is also template specialized for the GET and POST operations. 2. HTTPS connector. The libcurl library will be used to access the OCI Vault's endpoint. 3. API signing key. The OCI REST endpoints require the requests to be signed using an API signing key. The documentation about these keys is https://docs.cloud.oracle.com/en- us/iaas/Content/API/Concepts/apisigningkey.htm 4. Request Signature. The process of REST request signing is documented at https://docs.cloud.oracle.com/en- us/iaas/Content/API/Concepts/signingrequests.htm The Signing_key class from signing_keys.h takes care of signing the REST authorization header. 5. Common plugin interface The Keyring_OCI will use the keyring plugin interface that implements keyring service through the means of storing the keys in the OCI Vault. The Keyring_oci class from keyring_oci.h implements the keyring functionality for listing, reading, creating, uploading and deleting secrets. The oci.cc file implements the default keyring plugin interface to mysqld and handles plugin init/deinit.
Copyright (c) 2000, 2024, Oracle Corporation and/or its affiliates. All rights reserved.