database

package module
v0.0.0-...-1263d9b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2020 License: MPL-2.0 Imports: 43 Imported by: 0

README

vault-plugin-database-k8s-controller

A fork of Vault's database credential plugin allowing the use of an annotation on service accounts to dynamically specify user creation statements. Essentially, you can have many virtual 'roles' which each have tightly scoped database user creation statements, where the roles are in fact defined in Kubernetes. At Monzo we use this to allow for hundreds of Cassandra clients which each are allowed access to a single independent keyspace. Vault is not aware of individual services; simply logging in with your Kubernetes service account token is enough to get permission to issue the correct database credentials.

Non-builtin database plugins are not supported, as sadly custom plugins cannot call out to other custom plugins. However, all of Vault's builtin database plugins are bundled into this binary and should work as normal.

Currently based on https://github.com/hashicorp/vault/tree/v1.3.0/builtin/logical/database

To rebase:

make rebase

Instructions

This plugin differs from the default database plugin only if kubernetes config is provided

# if your plugin is registered as database-k8s
vault secrets enable -path=database -plugin-name=database-k8s database-k8s
vault write database/kubeconfig kubernetes_host=https://127.0.0.1 kubernetes_ca_cert=@cert jwt=@jwt

If this is provided, the plugin will attempt to maintain an in memory cache of all service accounts in Kubernetes. If any service accounts contain an annotation monzo.com/keyspace, the mapping from service account name to the annotation is also stored in Vault. This is so that the mapping can be used before the cache is built from the k8s API.

The purpose of this is to interpolate this annotation into any creation statements of a role, to create essentially a dynamic role for every service account. If you provide a role named like k8s_rw_s-ledger_default and this role does not explicitly exist then instead the plugin will look up the concrete role named rw, and will look up the service account s-ledger in the namespace default.

It will then replace all instances of {{annotation}} in the creation statements of the concrete rw role with the value of the annotation on that service account.

You can also set an annotation monzo.com/cluster which allows you to override the db name of the concrete rw role with the value of the annotation.

Annotation keys can be overridden with the kubeconfig endpoint, using keyspace_annotation and db_name_annotation.

The role names are designed such that they can support a vault policy as follows:

path "database/creds/k8s_rw_{{identity.entity.aliases.kubernetes.metadata.service_account_name}}_{{identity.entity.aliases.kubernetes.metadata.service_account_namespace}}"
{
  capabilities = ["read"]
}

The role name is used for these parameters so that the plugin has the same API as its upstream.

Example

$ vault write database/roles/rw \
    db_name=my-cassandra-database \
    creation_statements="CREATE USER '{{username}}' WITH PASSWORD '{{password}}' NOSUPERUSER;" \
    creation_statements="GRANT ALL PERMISSIONS ON KEYSPACE \"{{annotation}}\" TO {{username}};" \
    default_ttl="1h" \
    max_ttl="24h"
Success! Data written to: database/roles/rw

kubectl create serviceaccount s-ledger
kubectl annotate serviceaccount s-ledger monzo.com/keyspace='ledger'

$ vault read database/roles/k8s_rw_s-ledger_default
Key                      Value
---                      -----
creation_statements      [CREATE USER '{{username}}' WITH PASSWORD '{{password}}' NOSUPERUSER; GRANT ALL PERMISSIONS ON KEYSPACE "ledger" TO {{username}};]
db_name                  my-cassandra-database
default_ttl              1h
max_ttl                  24h
renew_statements         []
revocation_statements    []
rollback_statements      []

Documentation

Index

Constants

View Source
const SecretCredsType = "creds"

Variables

This section is empty.

Functions

func Backend

func Backend(conf *logical.BackendConfig) *databaseBackend

func Factory

func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error)

Types

type DatabaseConfig

type DatabaseConfig struct {
	PluginName string `json:"plugin_name" structs:"plugin_name" mapstructure:"plugin_name"`
	// ConnectionDetails stores the database specific connection settings needed
	// by each database type.
	ConnectionDetails map[string]interface{} `json:"connection_details" structs:"connection_details" mapstructure:"connection_details"`
	AllowedRoles      []string               `json:"allowed_roles" structs:"allowed_roles" mapstructure:"allowed_roles"`

	RootCredentialsRotateStatements []string `` /* 136-byte string literal not displayed */
}

DatabaseConfig is used by the Factory function to configure a Database object.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL