Issue:
When using the Terraform resource vault_database_secret_backend_connection
to create a database connection in HCP Vault dedicated, you may encounter the following error:
plugin not found in the catalog: oracle-database-plugin
The error arises because the Terraform provider is trying to reference the Oracle database plugin using the name "oracle-database-plugin," which does not match the actual plugin name "vault-plugin-database-oracle" used in HCP Vault.
Below are two solutions to resolve this issue, depending on your use case.
Solution 1: Use the vault_database_secrets_mount
Resource
This solution involves explicitly mounting the database secrets engine with the correct plugin configuration. Here's a sample Terraform configuration:
Sample Code:
terraform {
required_providers {
# Define the HCP provider for HashiCorp Cloud Platform
hcp = {
source = "hashicorp/hcp" # Source location for the HCP provider
version = "0.94.1" # Specify the version of the provider
}
# Define the Vault provider
vault = {
source = "hashicorp/vault" # Source location for the Vault provider
version = "3.23.0" # Specify the version of the provider
}
}
}
# Configure the Vault provider with the necessary address and token
provider "vault" {
address = "<hcp-vault-dedicated-address>" # The address of the dedicated HCP Vault instance
token = "<vault-token>" # Token for authenticating with Vault
}
# Mount a database secret backend for Oracle
resource "vault_database_secrets_mount" "oracle" {
path = "oracle-database" # Path under which the Oracle database backend will be mounted
oracle {
verify_connection = true # Enable connection verification for the database
plugin_name = "vault-plugin-database-oracle" # Specify the Oracle database plugin name
name = "<db-connection-name>" # Name of the database connection
allowed_roles = ["<role-name>"] # Roles allowed to access this connection
connection_url = "{{username}}/{{password}}@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=<hostname>)(PORT=<port-number>))(CONNECT_DATA=(SID=<sid-name>)))" # Format for connecting to the database
username = "<username>" # Username for the database connection
password = "<password>" # Password for the database connection
max_open_connections = 4 # Maximum number of open connections to the database
max_idle_connections = 0 # Maximum number of idle connections to retain (0 means no limit)
max_connection_lifetime = 0 # Maximum lifetime of a connection (0 means no limit)
}
}
# Define a static role for the database connection
resource "vault_database_secret_backend_static_role" "static_role_oracle" {
backend = "oracle-database" # Specify the backend path for the Oracle database
name = "<role-name>" # Name of the static role
db_name = "<db-connection-name>" # Database connection name associated with this role
username = "<username>" # Username for the database role
rotation_period = 864000 # Credential rotation period in seconds (10 days)
depends_on = [vault_database_secrets_mount.oracle] # Ensure this runs after the Oracle backend is mounted
}
Limitation:
When removing the database connection block, this solution recreates the entire vault_database_secrets_mount
resource, affecting other connections. If you have multiple database connections, this might not be the ideal approach.
Solution 2: Use the vault_generic_endpoint
Resource
To avoid recreating the entire mount resource and disrupting other connections, you can use the vault_generic_endpoint
resource. This approach allows more granular management of database connections without remounting.
Sample Code:
terraform {
required_providers {
# Define the HCP provider for HashiCorp Cloud Platform
hcp = {
source = "hashicorp/hcp" # Source location for the provider
version = "0.94.1" # Specify the version of the provider
}
# Define the Vault provider
vault = {
source = "hashicorp/vault" # Source location for the Vault provider
version = "3.23.0" # Specify the version of the provider
}
}
}
# Variable to hold the list of database connection names
variable "db_connection_names" {
description = "List of database connection names" # Description for the variable
type = list(string) # Type of variable: list of strings
default = ["oracle-connection", "oracle-connection2", "oracle-connection3"] # Default values
}
# Configure the Vault provider with the necessary address and token
provider "vault" {
address = "<vault-address>" # The address of the Vault server
token = "<vault-token>" # Token for authentication with Vault
}
# Mount a new database secret backend in Vault
resource "vault_mount" "db" {
path = "oracle-db-new" # Path under which the database backend will be mounted
type = "database" # Type of backend being mounted
}
# Configure database connections using a generic endpoint resource
resource "vault_generic_endpoint" "db_connection" {
for_each = toset(var.db_connection_names) # Iterate over each connection name
path = "${vault_mount.db.path}/config/${each.key}" # Path for the connection config
ignore_absent_fields = true # Ignore any absent fields during creation
data_json = <<EOT
{
"plugin_name": "vault-plugin-database-oracle", # Specify the plugin name for Oracle database
"allowed_roles": ["${each.key}-role"], # Define roles allowed to use this connection
"connection_url": "{{username}}/{{password}}@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=<hostname>)(PORT=<port-number>))(CONNECT_DATA=(SID=<sid-name>)))", # Connection URL format
"username": "<username>", # Database username
"password": "<password>" # Database password
}
EOT
}
# Define static roles for each database connection
resource "vault_database_secret_backend_static_role" "my-role" {
for_each = toset(var.db_connection_names) # Iterate over each connection name
name = "${each.key}-role" # Name of the role, derived from connection name
backend = "oracle-db-new" # Specify the backend path
db_name = each.key # Database name to associate with the role
username = "<username>" # Username for the database
rotation_period = 864000 # Rotation period for credentials (in seconds)
depends_on = [vault_generic_endpoint.db_connection] # Ensure this runs after the connection is created
}
Benefit:
With this approach, you can manage individual database connections without impacting other connections when a specific connection is updated or removed.
Conclusion:
Depending on your use case, either solution can resolve the error related to the oracle-database-plugin
when using Terraform to manage database connections in HCP Vault. The vault_database_secrets_mount
resource offers a straightforward approach, but for larger setups with multiple connections, the vault_generic_endpoint
resource provides better control without affecting other connections.
Resources:
https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/database_secrets_mount
https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/generic_endpoint
https://developer.hashicorp.com/vault/docs/secrets/databases