Vault configuration operator

This operator helps set up the vault configuration. The main intention is to do this so that subsequent pods can consume the provided secrets. There are two main principles that run through all the capabilities of this operator.

  1. High fidelity API. The CRD exposed by this operator reflects the Vault APIs field by field. This is because we don’t want to make any assumptions about the various configuration workflows that users will set up. That said, Vault’s API is very extensive, and we started with enough API coverage to support, we think, some simple and very common configuration workflows.
  2. Be security aware (we are integrating with security tools, after all). To prevent credentials from being leaked, we did not give the operator itself access to Vault. All apis exposed by this operator contain enough information to authenticate Vault using the local service account (the local account in the namespace where the API exists). In other words, for a user of a namespace to successfully configure Vault, the service account for that namespace must have the required Vault privileges in advance.

This operator currently supports the following CRDS.

  1. Policy Configures the Vault policy
  2. VaultRole Configures VaultKubernetes authentication roles
  3. SecretEngineMount Configures a mount point for SecretEngine.
  4. Secret DatabaseSecretEngineConfig configuration database engine connection.
  5. DatabaseSecretEngineRole configures the DatabaseSecretEngineRole
  6. RandomSecret creates a RandomSecret in vaultkv secret engine and generates a password field using PasswordPolicy.

Certification part

As discussed, each API has an authentication section that specifies how to authenticate Vault. Here’s an example.

  authentication: 
    path: kubernetes
    role: policy-admin
    namespace: tenant-namespace
    serviceAccount:
      name: vaultsa  
Copy the code

The path field specifies the installation path of the Kubernetes authentication role.

The role field specifies the role to request during authentication.

The Namespace field specifies the Vault namespace to use (independent of the Kubernetes namespace). This is optional.

Serviceaccount. name specifies which serviceAccount token to use during authentication.

Therefore, the above configuration roughly corresponds to the following commands.

vault write [tenant-namespace/]auth/kubernetes/login role=policy-admin jwt=
Copy the code

policy

Policy CRD allows users to create a [Vault Policy]. Here is an example.

apiVersion: redhatcop.redhat.io/v1alpha1
kind: Policy
metadata:
  name: database-creds-reader
spec:
  authentication: 
    path: kubernetes
    role: policy-admin
  policy: |
    # Configure read secrets
    path "/{{identity.entity.aliases.auth_kubernetes_804f1655.metadata.service_account_namespace}}/database/creds/+" {
      capabilities = ["read"]
    }

Copy the code

Notice that in this policy, we parameterize the path based on the namespace of the connection service account.

VaultRole

VaultRole, for example, creates a Vault authentication role for Kubernetes authentication mount.

apiVersion: redhatcop.redhat.io/v1alpha1
kind: VaultRole
metadata:
  name: database-engine-admin
spec:
  authentication: 
    path: kubernetes
    role: policy-admin
  path: kubernetes  
  policies:
    - database-engine-admin
  targetServiceAccounts: 
  - vaultsa  
  targetNamespaceSelector:
    matchLabels:
      postgresql-enabled: "true"
Copy the code

The path field specifies the Kubernetes authentication mount path where the role will be mounted.

The Policies field specifies which Vault policies will be associated with this role.

The targetServiceAccounts field specifies which service accounts can be authenticated. If not specified, it defaults to default.

The targetNamespaceSelector field specifies which Kubernetes namespaces can be authenticated from. Note that this configuration will be updated as the set of namespaces selected by the selector changes. You can also specify a static set of namespaces.

Many other standard Kubernetes authentication role fields are available for fine-tuning, see Vault documentation

This CR is roughly equivalent to the Vault CLI command.

vault write [namespace/]auth/kubernetes/role/database-engine-admin bound_service_account_names=vaultsa bound_service_account_namespaces=
Copy the code

SecretEngineMount

SecretEngineMount CRD allows the user to create a SecretEngineMount point, as shown in the following example.

apiVersion: redhatcop.redhat.io/v1alpha1
kind: SecretEngineMount
metadata:
  name: database
spec:
  authentication: 
    path: kubernetes
    role: database-engine-admin
  type: database
  path: postgresql-vault-demo

Copy the code

The type field specifies the type of the secret engine.

The path field specifies the path to install the secret engine.

Many other standard secret engine mount fields are available for fine-tuning, see the Vault documentation.

This CR is roughly equivalent to the Vault CLI command.

vault secrets 
Copy the code

DatabaseSecretEngineConfig

Secret DatabaseSecretEngineConfig CRD allows the user to create a database engine configuration, also known as the secret existing database engine installation of connection. Here’s an example

apiVersion: redhatcop.redhat.io/v1alpha1
kind: DatabaseSecretEngineConfig
metadata:
  name: my-postgresql-database
spec:
  authentication: 
    path: kubernetes
    role: database-engine-admin
  pluginName: postgresql-database-plugin
  allowedRoles:
    - read-write
    - read-only
  connectionURL: postgresql://{{username}}:{{password}}@my-postgresql-database.postgresql-vault-demo.svc:5432
  username: admin
  rootCredentialsFromSecret:
    name: postgresql-admin-password
  path: postgresql-vault-demo/database
Copy the code

The pluginName field specifies what type of database this connection is for.

The allowedRoles field specifies which role names can be created for this connection.

The connectionURL field specifies how to connect to the database.

The username field specifies the username used to connect to the database. This field is optional; if not specified, the username is taken from the credential secret.

The path field specifies the path to the secret engine to which the connection will be added.

Passwords and possible user names can be obtained in three different ways.

  1. Secret from Kubernetes, specifiedrootCredentialsFromSecretField. The secret must beBasic Authentication Type. If the secret is updated, the connection is updated as well.
  2. Secret from Vault, specifiedrootCredentialsFromVaultSecretField.
  3. From aRandomSecret, specifyrootCredentialsFromRandomSecretField. When RandomSecret generates a new secret, the connection will also be updated.

Many other standard database secret engine configuration fields are available for fine-tuning, see Vault documentation

This CR is roughly equivalent to the Vault CLI command.

vault write [namespace/]auth/kubernetes/role/database-engine-admin bound_service_account_names=vaultsa Bound_service_account_namespaces = < dynamic generation > policies=database-engine-admin

[](#databasesecretenginerole)DatabaseSecretEngineRole ----------------------------------------------------- 'DatabaseSecretEngineRole' CRD allows the user to create a DatabaseSecretEngineRole. Here is an example. apiVersion: redhatcop.redhat.io/v1alpha1 kind: DatabaseSecretEngineRole metadata: name: read-only spec: authentication: path: kubernetes role: database-engine-admin path: postgresql-vault-demo/database dBName: my-postgresql-database creationStatements: - CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";Copy the code

The path field specifies the path to the secret engine that will contain this role.

The dBname field specifies the name of the connection to be used with this role.

The creationStatements field specifies the statement to run to create a new account.

Many other standard database secret engine role fields are available for fine-tuning, see Vault documentation

This CR is roughly equivalent to the Vault CLI command.

vault write [namespace/]postgresql-vault-demo/database/config/my-postgresql-database plugin_name=postgresql-database-plugin allowed_roles="read-write,read-only" connection_url="postgresql://{{username}}:{{password}}@my-postgresql-database.postgresql-vault-demo.svc:5432/" username=<retrieved dynamically> password=<retrieved dynamically>
Copy the code

RandomSecret

RandomSecret CRD allows the user to generate a RandomSecret (usually a password) and store it in a given key in Vault. The generated secret will comply with Vault’s [password policy], here is an example.

apiVersion: redhatcop.redhat.io/v1alpha1
kind: RandomSecret
metadata:
  name: my-postgresql-admin-password
spec:
  authentication: 
    path: kubernetes
    role: database-engine-admin
  path: kv/vault-tenant
  secretKey: password
  secretFormat:
    passwordPolicyName: my-complex-password-format
  refreshPeriod: 1h
Copy the code

The path field specifies the path where the secret will be written, and it must correspond to the installation of the KV secret engine.

The secretKey field is the key for the secret.

SecretFormat is a reference to the Vault Password policy, which can also be provided inline.

RefreshPeriod specifies the secret regeneration frequency. This is an optional field, if not specified, the secret will be generated once and then not updated again.

With RandomSecret, it is possible to set up a workflow in which the root password of the resource we need to protect is never stored anywhere but in the vault. One way to do this is to seed the root password with a random secret. Then create an operator, observe RandomSecret, retrieve the generated secret from the vault, and update the resource to be protected. Finally, configure the secret engine object to monitor RandomSecret updates.

This CR is roughly equivalent to the Vault CLI command.

vault kv put [namespace/]kv/vault-tenant password=
Copy the code

GitHub

Github.com/raffaelespa…