tools/ocivaultgen.py (115 lines of code) (raw):

#!/usr/bin/env python # Copyright (c) 2022, Oracle and/or its affiliates. # # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ # """ Generate MySQL configuration for usage with OCI Key Vault This script guides interatively thorugh the selection of OCI Key Vault settings and will, where need be, offer to create a Vault and Key with some default settings. Those default settings, like software based key storage, key len, etc. may not be best practice for production use and are ment for testing or experimental use. Production grade configuration should be made elsewhere. This script then may still be useful for generating the MySQL Server or MySQL Operator configuration. This script is meant for interactive use. """ try: import oci except ModuleNotFoundError as exc: import sys print(f"Failed to load OCI module: {exc}", file=sys.stderr) sys.exit(1) def menu(items): if len(items) == 1: return items[0][1] i = 0 for item in items: i = i + 1 print(f"\033[0;32m{i:2}) \033[0;33m{item[0]}\033[0m") response = input(f"Pick 1 to {i}: ") try: selection = int(response) except ValueError: selection = 0 if selection < 1 or selection > i: return menu(items) return items[selection-1][1] def pick_profile(): profile = input("\033[0;33mProfile:\033[0m ") if not profile: profile="DEFAULT" try: return oci.config.from_file(profile_name=profile) except Exception as exc: print(f"\033[0;31mFailed to find profile \033[0;33m{profile}\033[0m: {exc}") return pick_profile() def pick_compartment(identity: oci.identity.IdentityClient, current): """Let user recursively pick the compartment they need""" my = identity.get_compartment(current).data print(f"Current compartment {my.name} ({my.description})\n") compartments = identity.list_compartments(current) choices = [['Current', my]] + list(map(lambda item: [item.name, item], compartments.data)) pick = menu(choices) if pick != my: return pick_compartment(identity, pick.id) return my def no_https(input): return input.replace("https://", "") config = pick_profile() identity_client = oci.identity.IdentityClient(config) compartment = pick_compartment(identity_client, config["tenancy"]) print(f"\033[0;33mCompartment picked: \033[0;32m{compartment.name} \033[0m({compartment.description})") print("\033[0;33mPick Vault:\033[0m") vault_client = oci.key_management.KmsVaultClient(config) choices = list(map(lambda item: [f"{item.display_name} ({item.lifecycle_state})", item], vault_client.list_vaults(compartment.id).data)) vault = menu(choices + [["Create a New Vault", None]]) if not vault: vault_client_composite = oci.key_management.KmsVaultClientCompositeOperations(vault_client) vault_details = oci.key_management.models.CreateVaultDetails( compartment_id=compartment.id, vault_type="DEFAULT", display_name=input("Display Name of new vault: ")) print("Creating and waiting to be ready ...") vault = vault_client_composite.create_vault_and_wait_for_state( vault_details, wait_for_states=[oci.key_management.models.Vault.LIFECYCLE_STATE_ACTIVE]).data print(f"Vault picked: {vault.display_name}") print("\033[0;33mSelect Master Key:\033[0m") kms_client = oci.key_management.KmsManagementClient(config, vault.management_endpoint) choices = list(map(lambda item: [f"{item.display_name} ({item.lifecycle_state})", item], kms_client.list_keys(compartment.id).data)) key = menu(choices + [["Create a New Key", None]]) if not key: kms_client_composite = oci.key_management.KmsManagementClientCompositeOperations(kms_client) key_shape = oci.key_management.models.KeyShape(algorithm="AES", length=32) key_details = oci.key_management.models.CreateKeyDetails( compartment_id=compartment.id, display_name=input("Display Name for new Key: "), protection_mode=oci.key_management.models.CreateKeyDetails.PROTECTION_MODE_SOFTWARE, key_shape=key_shape) print("Creating key and waiting to be ready ...") key = kms_client_composite.create_key_and_wait_for_state(key_details, wait_for_states=[oci.key_management.models.Key.LIFECYCLE_STATE_ENABLED]).data print(f"Key picked: {key.display_name}") def ask_format(): while True: result = menu([["my.cnf (MySQL Plugin)", "mycnf"], ["component_keyring_oci.cnf (MySQL Component)", "component"], ["Operator YAML", "yaml"], ["End", "end"]]) if result == "end": return yield result for format in ask_format(): if format == "mycnf": print("\n\033[0;32mYour MySQL Config:\033[0m") print(f""" [mysqld] early-plugin-load=keyring_oci.so keyring_oci_user={config['user']} keyring_oci_tenancy={config['tenancy']} keyring_oci_compartment={compartment.id} keyring_oci_virtual_vault={vault.id} keyring_oci_master_key={key.id} keyring_oci_encryption_endpoint={no_https(vault.crypto_endpoint)} keyring_oci_management_endpoint={no_https(vault.management_endpoint)} keyring_oci_vaults_endpoint=vaults.{config['region']}.oci.oraclecloud.com keyring_oci_secrets_endpoint=secrets.vaults.{config['region']}.oci.oraclecloud.com keyring_oci_key_file={config['key_file']} keyring_oci_key_fingerprint={config['fingerprint']} """) if format == "yaml": print("\n\033[0;32mYour MySQL Operator Config:\033[0m") print(f""" keyring: oci: user: {config['user']} keySecret: oci-vault-key keyFingerprint: {config['fingerprint']} tenancy: {config['tenancy']} compartment: {compartment.id} virtualVault: {vault.id} masterKey: {key.id} endpoints: encryption: {no_https(vault.crypto_endpoint)} management: {no_https(vault.management_endpoint)} vaults: vaults.{config['region']}.oci.oraclecloud.com secrets: secrets.vaults.{config['region']}.oci.oraclecloud.com \n\033[0;32mRun this command to create the secret containing the key:\033[0m kubectl create secret generic \\ -n YOUR_K8S_NAMESPACE oci-vault-key \\ --from-file=privatekey={config['key_file']} """) if format == "component": import json print("\n\033[0;32mYour MySQL Server Component Config \033[0;33mmysqld.my\033[0;32m:\033[0m") mysqldmy = {"components": "file://component_keyring_oci"} print(json.dumps(mysqldmy, indent=2)) print("\n\033[0;32mYour MySQL Server Component Config \033[0;33mcomponent_keyring_oci.cnf\033[0;32m:\033[0m") component = { "user": config['user'], "key_file": config['key_file'], "key_fingerprint": config['fingerprint'], "tenancy": config['tenancy'], "compartment": compartment.id, "virtual_vault": vault.id, "master_key": key.id, "encryption_endpoint": no_https(vault.crypto_endpoint), "management_endpoint": no_https(vault.management_endpoint), "vaults_endpoint": f"vaults.{config['region']}.oci.oraclecloud.com", "secrets_endpoint": f"secrets.vaults.{config['region']}.oci.oraclecloud.com", } print(json.dumps(component, indent=2))