From 116aa9e887df1497cb64523bc1e6ddfaa4fd4c00 Mon Sep 17 00:00:00 2001 From: 1gtm <1gtm@appscode.com> Date: Sun, 23 Nov 2025 18:40:14 +0000 Subject: [PATCH] Prepare for release v2025.11.21 ProductLine: KubeVault Release: v2025.11.21 Release-tracker: https://github.com/kubevault/CHANGELOG/pull/61 Signed-off-by: 1gtm <1gtm@appscode.com> --- .../docs/v2025.11.21/CHANGELOG-v2021.08.02.md | 828 ++++ .../docs/v2025.11.21/CHANGELOG-v2021.09.27.md | 111 + .../docs/v2025.11.21/CHANGELOG-v2021.10.11.md | 91 + .../docs/v2025.11.21/CHANGELOG-v2022.01.11.md | 97 + .../docs/v2025.11.21/CHANGELOG-v2022.02.22.md | 87 + .../docs/v2025.11.21/CHANGELOG-v2022.06.16.md | 119 + .../v2025.11.21/CHANGELOG-v2022.09.05-rc.0.md | 74 + .../docs/v2025.11.21/CHANGELOG-v2022.09.09.md | 79 + .../docs/v2025.11.21/CHANGELOG-v2022.09.22.md | 78 + .../docs/v2025.11.21/CHANGELOG-v2022.11.30.md | 75 + .../docs/v2025.11.21/CHANGELOG-v2022.12.09.md | 71 + .../docs/v2025.11.21/CHANGELOG-v2022.12.28.md | 71 + .../docs/v2025.11.21/CHANGELOG-v2023.03.03.md | 81 + .../docs/v2025.11.21/CHANGELOG-v2023.05.05.md | 88 + .../docs/v2025.11.21/CHANGELOG-v2023.9.7.md | 92 + .../v2025.11.21/CHANGELOG-v2024.1.26-rc.0.md | 75 + .../v2025.11.21/CHANGELOG-v2024.1.28-rc.1.md | 70 + .../docs/v2025.11.21/CHANGELOG-v2024.1.31.md | 92 + .../docs/v2025.11.21/CHANGELOG-v2024.3.12.md | 70 + .../docs/v2025.11.21/CHANGELOG-v2024.9.30.md | 85 + .../docs/v2025.11.21/CHANGELOG-v2025.11.21.md | 112 + .../docs/v2025.11.21/CHANGELOG-v2025.2.10.md | 126 + .../v2025.11.21/CHANGELOG-v2025.2.6-rc.0.md | 112 + .../docs/v2025.11.21/CHANGELOG-v2025.5.26.md | 98 + .../docs/v2025.11.21/CHANGELOG-v2025.5.30.md | 67 + content/docs/v2025.11.21/CONTRIBUTING.md | 60 + content/docs/v2025.11.21/README.md | 66 + content/docs/v2025.11.21/_index.md | 17 + content/docs/v2025.11.21/concepts/README.md | 150 + content/docs/v2025.11.21/concepts/_index.md | 16 + .../docs/v2025.11.21/concepts/architecture.md | 38 + .../concepts/backup-restore/_index.md | 17 + .../concepts/backup-restore/overview.md | 87 + content/docs/v2025.11.21/concepts/overview.md | 97 + .../concepts/policy-crds/_index.md | 17 + .../concepts/policy-crds/vaultpolicy.md | 125 + .../policy-crds/vaultpolicybinding.md | 178 + .../concepts/secret-engine-crds/_index.md | 17 + .../aws-secret-engine/_index.md | 17 + .../aws-secret-engine/awsrole.md | 192 + .../azure-secret-engine/_index.md | 17 + .../azure-secret-engine/azurerole.md | 140 + .../database-secret-engine/_index.md | 17 + .../database-secret-engine/elasticsearch.md | 129 + .../database-secret-engine/mariadb.md | 135 + .../database-secret-engine/mongodb.md | 135 + .../database-secret-engine/mysql.md | 135 + .../database-secret-engine/postgresrole.md | 147 + .../database-secret-engine/redis.md | 132 + .../gcp-secret-engine/_index.md | 17 + .../gcp-secret-engine/gcprole.md | 139 + .../pki-secret-engine/_index.md | 17 + .../pki-secret-engine/pkirole.md | 145 + .../secret-access-request.md | 190 + .../secret-engine-crds/secret-role-binding.md | 328 ++ .../secret-engine-crds/secretengine.md | 580 +++ .../concepts/tls-encryption/_index.md | 17 + .../concepts/tls-encryption/configuration.md | 127 + .../concepts/tls-encryption/overview.md | 118 + .../concepts/vault-ops-request/_index.md | 17 + .../concepts/vault-ops-request/overview.md | 210 + .../concepts/vault-server-crds/_index.md | 17 + .../concepts/vault-server-crds/appbinding.md | 285 ++ .../vault-server-crds/auth-methods/_index.md | 17 + .../auth-methods/appbinding.md | 156 + .../vault-server-crds/auth-methods/aws-iam.md | 89 + .../vault-server-crds/auth-methods/azure.md | 95 + .../vault-server-crds/auth-methods/gcp-iam.md | 81 + .../auth-methods/jwt-oidc.md | 97 + .../auth-methods/kubernetes.md | 149 + .../auth-methods/overview.md | 34 + .../vault-server-crds/auth-methods/tls.md | 83 + .../vault-server-crds/auth-methods/token.md | 62 + .../auth-methods/userpass.md | 80 + .../vault-server-crds/storage/_index.md | 17 + .../vault-server-crds/storage/azure.md | 101 + .../vault-server-crds/storage/consul.md | 322 ++ .../vault-server-crds/storage/dynamodb.md | 167 + .../vault-server-crds/storage/etcd.md | 140 + .../vault-server-crds/storage/filesystem.md | 144 + .../concepts/vault-server-crds/storage/gcs.md | 112 + .../vault-server-crds/storage/inmem.md | 46 + .../vault-server-crds/storage/mysql.md | 127 + .../vault-server-crds/storage/overview.md | 47 + .../vault-server-crds/storage/postgresql.md | 87 + .../vault-server-crds/storage/raft.md | 145 + .../concepts/vault-server-crds/storage/s3.md | 154 + .../vault-server-crds/storage/swift.md | 198 + .../vault-server-crds/unsealer/_index.md | 17 + .../vault-server-crds/unsealer/aws_kms_ssm.md | 88 + .../unsealer/azure_key_vault.md | 118 + .../unsealer/google_kms_gcs.md | 112 + .../unsealer/kubernetes_secret.md | 45 + .../vault-server-crds/unsealer/overview.md | 102 + .../concepts/vault-server-crds/vaultserver.md | 363 ++ .../vault-server-crds/vaultserverversion.md | 101 + .../backup-restore/backup-configuration.yaml | 26 + .../guides/backup-restore/repository.yaml | 15 + .../backup-restore/restore-session.yaml | 20 + .../guides/backup-restore/vaultserver.yaml | 30 + .../policy-management/policy-reader-role.yaml | 16 + .../policy-management/read-only-policy.yaml | 16 + .../guides/policy-management/vaultserver.yaml | 16 + .../policy-management/vaultserverversion.yaml | 13 + .../guides/provider/aks/my-vault.yaml | 21 + .../provider/aks/vaultserverversion.yaml | 13 + .../guides/provider/eks/my-vault.yaml | 20 + .../provider/external-vault/demo-policy.yaml | 12 + .../external-vault/policy-admin-sa.yaml | 5 + .../provider/external-vault/policy-admin.hcl | 15 + .../external-vault/token-review-binding.yaml | 12 + .../external-vault/token-reviewer-sa.yaml | 5 + .../provider/external-vault/vault-app.yaml | 15 + .../guides/provider/external-vault/vault.yaml | 46 + .../guides/provider/gke/my-vault.yaml | 23 + .../provider/gke/vaultserverversion.yaml | 12 + .../demo-policy-secret-admin.yaml | 12 + .../demo-policy-secret-reader.yaml | 12 + .../provider/multi-cluster/my-vault.yaml | 34 + .../provider/multi-cluster/vault-app.yaml | 11 + .../provider/multi-cluster/vault-token.yaml | 8 + .../multi-cluster/vaultserverversion.yaml | 12 + .../guides/secret-engines/aws/pod.yaml | 22 + .../guides/secret-engines/aws/policy.yaml | 12 + .../secret-engines/aws/policybinding.yaml | 16 + .../aws/secret-role-binding.yaml | 13 + .../guides/secret-engines/aws/secret.yaml | 8 + .../secret-engines/aws/secretengine.yaml | 14 + .../secret-engines/aws/secretenginerole.yaml | 20 + .../aws/secretproviderclass.yaml | 17 + .../secret-engines/aws/serviceaccount.yaml | 5 + .../secret-engines/aws/vaultserver.yaml | 38 + .../guides/secret-engines/azure/pod.yaml | 22 + .../guides/secret-engines/azure/policy.yaml | 12 + .../secret-engines/azure/policybinding.yaml | 16 + .../azure/secret-role-binding.yaml | 13 + .../guides/secret-engines/azure/secret.yaml | 10 + .../secret-engines/azure/secretengine.yaml | 10 + .../azure/secretenginerole.yaml | 10 + .../azure/secretproviderclass.yaml | 17 + .../secret-engines/azure/serviceaccount.yaml | 5 + .../secret-engines/azure/vaultserver.yaml | 38 + .../elasticsearch/elasticsearch.yaml | 18 + .../secret-engines/elasticsearch/pod.yaml | 22 + .../secret-engines/elasticsearch/policy.yaml | 12 + .../elasticsearch/policybinding.yaml | 16 + .../elasticsearch/secret-role-binding.yaml | 13 + .../elasticsearch/secretengine.yaml | 13 + .../elasticsearch/secretenginerole.yaml | 12 + .../elasticsearch/secretproviderclass.yaml | 17 + .../elasticsearch/serviceaccount.yaml | 5 + .../elasticsearch/vaultserver.yaml | 38 + .../guides/secret-engines/gcp/pod.yaml | 22 + .../guides/secret-engines/gcp/policy.yaml | 12 + .../secret-engines/gcp/policybinding.yaml | 16 + .../gcp/secret-role-binding.yaml | 13 + .../guides/secret-engines/gcp/secret.yaml | 7 + .../secret-engines/gcp/secretengine.yaml | 10 + .../secret-engines/gcp/secretenginerole.yaml | 16 + .../gcp/secretproviderclass.yaml | 14 + .../secret-engines/gcp/serviceaccount.yaml | 5 + .../secret-engines/gcp/vaultserver.yaml | 38 + .../guides/secret-engines/kv/pod.yaml | 21 + .../guides/secret-engines/kv/policy.yaml | 12 + .../secret-engines/kv/policybinding.yaml | 16 + .../kv/secretproviderclass.yaml | 14 + .../secret-engines/kv/serviceaccount.yaml | 5 + .../guides/secret-engines/kv/vaultserver.yaml | 38 + .../secret-engines/mariadb/mariadb.yaml | 16 + .../guides/secret-engines/mariadb/pod.yaml | 22 + .../guides/secret-engines/mariadb/policy.yaml | 12 + .../secret-engines/mariadb/policybinding.yaml | 16 + .../mariadb/secret-role-binding.yaml | 13 + .../secret-engines/mariadb/secretengine.yaml | 13 + .../mariadb/secretenginerole.yaml | 13 + .../mariadb/secretproviderclass.yaml | 17 + .../mariadb/serviceaccount.yaml | 5 + .../secret-engines/mariadb/vaultserver.yaml | 38 + .../secret-engines/mongodb/mongodb.yaml | 16 + .../guides/secret-engines/mongodb/pod.yaml | 22 + .../guides/secret-engines/mongodb/policy.yaml | 12 + .../secret-engines/mongodb/policybinding.yaml | 16 + .../secret-engines/mongodb/secretengine.yaml | 13 + .../mongodb/secretenginerole.yaml | 12 + .../mongodb/secretproviderclass.yaml | 17 + .../mongodb/secretrolebinding.yaml | 13 + .../mongodb/serviceaccount.yaml | 5 + .../secret-engines/mongodb/vaultserver.yaml | 38 + .../guides/secret-engines/mysql/mysql.yaml | 16 + .../guides/secret-engines/mysql/pod.yaml | 22 + .../guides/secret-engines/mysql/policy.yaml | 12 + .../secret-engines/mysql/policybinding.yaml | 16 + .../mysql/secret-role-binding.yaml | 13 + .../secret-engines/mysql/secretengine.yaml | 13 + .../mysql/secretenginerole.yaml | 13 + .../mysql/secretproviderclass.yaml | 17 + .../secret-engines/mysql/serviceaccount.yaml | 5 + .../secret-engines/mysql/vaultserver.yaml | 38 + .../guides/secret-engines/pki/pod.yaml | 22 + .../guides/secret-engines/pki/policy.yaml | 12 + .../secret-engines/pki/policybinding.yaml | 16 + .../pki/secretproviderclass.yaml | 42 + .../secret-engines/pki/serviceaccount.yaml | 5 + .../secret-engines/pki/vaultserver.yaml | 38 + .../guides/secret-engines/postgres/pod.yaml | 22 + .../secret-engines/postgres/policy.yaml | 12 + .../postgres/policybinding.yaml | 16 + .../secret-engines/postgres/postgres.yaml | 16 + .../secret-engines/postgres/secretengine.yaml | 13 + .../postgres/secretenginerole.yaml | 13 + .../postgres/secretproviderclass.yaml | 17 + .../postgres/secretrolebinding.yaml | 13 + .../postgres/serviceaccount.yaml | 5 + .../secret-engines/postgres/vaultserver.yaml | 38 + .../guides/secret-engines/redis/pod.yaml | 22 + .../guides/secret-engines/redis/redis.yaml | 17 + .../redis/redisaccessrequest.yaml | 13 + .../redis/secret-role-binding.yaml | 13 + .../secret-engines/redis/secretengine.yaml | 14 + .../redis/secretenginerole.yaml | 12 + .../redis/secretproviderclass.yaml | 19 + .../secret-engines/redis/serviceaccount.yaml | 5 + .../secret-engines/redis/vaultserver.yaml | 27 + .../secret-access-request/secret.yaml | 8 + .../secretaccessrequest.yaml | 13 + .../secret-access-request/secretengine.yaml | 14 + .../secretenginerole.yaml | 20 + .../secret-access-request/serviceaccount.yaml | 5 + .../secret-access-request/vaultserver.yaml | 38 + .../secret-role-binding/secret.yaml | 8 + .../secret-role-binding/secretengine.yaml | 14 + .../secret-role-binding/secretenginerole.yaml | 20 + .../secretrolebinding.yaml | 13 + .../secret-role-binding/serviceaccount.yaml | 5 + .../secret-role-binding/vaultserver.yaml | 38 + .../guides/vault-ops-request/issuer.yaml | 8 + .../guides/vault-ops-request/new-issuer.yaml | 8 + .../vault-ops-request/vault-ops-add-tls.yaml | 21 + .../vault-ops-change-issuer.yaml | 14 + .../vault-ops-request/vault-ops-remove.yaml | 11 + .../vault-ops-request/vault-ops-rotate.yaml | 11 + .../guides/vault-ops-request/vaultserver.yaml | 32 + .../guides/vault-server/appBinding.yaml | 17 + .../examples/guides/vault-server/ca.crt | 17 + .../vault-server/clusterRoleBinding.yaml | 12 + .../guides/vault-server/secret-policy.yaml | 17 + .../examples/guides/vault-server/vault.hcl | 27 + .../guides/vault-server/vaultserver.yaml | 23 + .../vault-server/vaultserverversion.yaml | 12 + .../csi-driver/prom-builtin-conf.yaml | 102 + .../csi-driver/prom-builtin-deployment.yaml | 49 + .../csi-driver/prom-coreos-crd.yaml | 18 + .../monitoring/grafana/dashboard.json | 3390 +++++++++++++++++ .../prom-builtin-deployment.yaml | 49 + .../vault-operator/prom-coreos-crd.yaml | 18 + .../vault-operator/prom-server-conf.yaml | 52 + .../vault-operator/prometheus-builtin.yaml | 100 + .../prometheus-coreos-operator.yaml | 108 + .../vault-operator/prometheus-coreos.yaml | 68 + .../vault-operator/prometheus-service.yaml | 14 + .../vault-operator/vault-server-builtin.yaml | 32 + .../vault-operator/vault-server-coreos.yaml | 32 + .../vault-server/prom-server-conf.yaml | 46 + .../vault-server/prometheus-builtin.yaml | 90 + .../prometheus-coreos-operator.yaml | 108 + .../vault-server/prometheus-coreos.yaml | 68 + .../vault-server/prometheus-service.yaml | 14 + .../vault-server/vault-server-builtin.yaml | 32 + .../vault-server/vault-server-coreos.yaml | 32 + .../vaultserver_inmem_k8s_unsealer.yaml | 16 + content/docs/v2025.11.21/guides/README.md | 59 + content/docs/v2025.11.21/guides/_index.md | 16 + .../guides/backup-restore/_index.md | 17 + .../guides/backup-restore/backup.md | 371 ++ .../guides/backup-restore/overview.md | 201 + .../guides/backup-restore/restore.md | 188 + .../v2025.11.21/guides/monitoring/_index.md | 17 + .../v2025.11.21/guides/monitoring/overview.md | 86 + .../monitoring/vault-operator/_index.md | 17 + .../monitoring/vault-operator/builtin.md | 308 ++ .../monitoring/vault-operator/coreos.md | 210 + .../guides/monitoring/vault-server/_index.md | 17 + .../guides/monitoring/vault-server/builtin.md | 229 ++ .../guides/monitoring/vault-server/coreos.md | 104 + .../guides/monitoring/vault-server/grafana.md | 118 + .../v2025.11.21/guides/platforms/_index.md | 17 + .../docs/v2025.11.21/guides/platforms/aks.md | 366 ++ .../docs/v2025.11.21/guides/platforms/eks.md | 390 ++ .../guides/platforms/external-vault.md | 214 ++ .../docs/v2025.11.21/guides/platforms/gke.md | 373 ++ .../guides/platforms/multi-cluster-vault.md | 224 ++ .../guides/policy-management/_index.md | 17 + .../guides/policy-management/overview.md | 356 ++ .../guides/secret-engines/_index.md | 17 + .../guides/secret-engines/aws/_index.md | 17 + .../guides/secret-engines/aws/csi-driver.md | 293 ++ .../guides/secret-engines/aws/overview.md | 363 ++ .../guides/secret-engines/azure/_index.md | 17 + .../guides/secret-engines/azure/csi-driver.md | 293 ++ .../guides/secret-engines/azure/overview.md | 361 ++ .../secret-engines/csi_architecture.svg | 1 + .../secret-engines/elasticsearch/_index.md | 17 + .../elasticsearch/csi-driver.md | 292 ++ .../secret-engines/elasticsearch/overview.md | 337 ++ .../guides/secret-engines/gcp/_index.md | 17 + .../guides/secret-engines/gcp/csi-driver.md | 288 ++ .../guides/secret-engines/gcp/overview.md | 343 ++ .../guides/secret-engines/kv/_index.md | 17 + .../guides/secret-engines/kv/csi-driver.md | 326 ++ .../guides/secret-engines/kv/overview.md | 352 ++ .../guides/secret-engines/mariadb/_index.md | 17 + .../secret-engines/mariadb/csi-driver.md | 297 ++ .../guides/secret-engines/mariadb/overview.md | 337 ++ .../guides/secret-engines/mongodb/_index.md | 17 + .../secret-engines/mongodb/csi-driver.md | 295 ++ .../guides/secret-engines/mongodb/overview.md | 336 ++ .../guides/secret-engines/mysql/_index.md | 17 + .../guides/secret-engines/mysql/csi-driver.md | 297 ++ .../guides/secret-engines/mysql/overview.md | 337 ++ .../guides/secret-engines/pki/_index.md | 17 + .../guides/secret-engines/pki/csi-driver.md | 406 ++ .../guides/secret-engines/pki/overview.md | 458 +++ .../guides/secret-engines/postgres/_index.md | 17 + .../secret-engines/postgres/csi-driver.md | 297 ++ .../secret-engines/postgres/overview.md | 338 ++ .../guides/secret-engines/redis/_index.md | 17 + .../guides/secret-engines/redis/csi-driver.md | 340 ++ .../guides/secret-engines/redis/overview.md | 382 ++ .../guides/vault-ops-request/_index.md | 17 + .../guides/vault-ops-request/overview.md | 53 + .../vault-ops-request/reconfigure_tls.md | 416 ++ .../v2025.11.21/guides/vault-server/_index.md | 17 + .../guides/vault-server/auth-method.md | 225 ++ .../vault-server/external-vault-sever.md | 326 ++ .../guides/vault-server/overview.md | 51 + .../guides/vault-server/vault-server.md | 298 ++ .../images/concepts/architecture.svg | 632 +++ .../v2025.11.21/images/concepts/aws_role.svg | 324 ++ .../images/concepts/azure_role.svg | 323 ++ .../v2025.11.21/images/concepts/backup.svg | 192 + .../images/concepts/elasticsearch_role.svg | 1 + .../v2025.11.21/images/concepts/gcp_role.svg | 323 ++ .../images/concepts/mariadb_role.svg | 406 ++ .../images/concepts/mongodb_role.svg | 374 ++ .../images/concepts/mysql_role.svg | 373 ++ .../v2025.11.21/images/concepts/pki_role.svg | 1 + .../images/concepts/postgres_role.svg | 373 ++ .../images/concepts/redis_role.svg | 1 + .../v2025.11.21/images/concepts/restore.svg | 162 + .../images/concepts/secret_access_request.svg | 1 + .../images/concepts/vault_policy.svg | 323 ++ .../images/concepts/vault_policy_binding.svg | 368 ++ .../images/concepts/vault_server.svg | 762 ++++ .../images/csi-driver-policy-aws.jpg | Bin 0 -> 52367 bytes .../images/guides/backup-restore/backup.png | Bin 0 -> 46149 bytes .../guides/policy-management/vault_policy.svg | 323 ++ .../vault_policy_binding.svg | 368 ++ .../images/guides/provider/aks/aks.png | Bin 0 -> 85332 bytes .../images/guides/provider/aks/key-vault.png | Bin 0 -> 29775 bytes .../images/guides/provider/aks/root-token.png | Bin 0 -> 80571 bytes .../guides/provider/aks/secret-access.png | Bin 0 -> 36143 bytes .../guides/provider/aks/unseal-keys.png | Bin 0 -> 54157 bytes .../guides/provider/eks/aws-instance.png | Bin 0 -> 31706 bytes .../guides/provider/eks/unseal-keys.png | Bin 0 -> 73890 bytes .../guides/provider/gke/gke-cluster.png | Bin 0 -> 20659 bytes .../guides/provider/gke/gke-unseal-keys.png | Bin 0 -> 83864 bytes .../provider/multi-cluster/gke-cluster.png | Bin 0 -> 35861 bytes .../aws/aws_secret_engine_guide.svg | 864 +++++ .../azure/azure_secret_engine_guide.svg | 864 +++++ .../elasticsearch_secret_engine_guide.svg | 1 + .../guides/secret-engines/gcp/gcp_guide.svg | 865 +++++ .../mariadb/mariadb_secret_engine_guide.svg | 1 + .../mongodb/mongodb_secret_engine_guide.svg | 864 +++++ .../mysql/mysql_secret_engine_guide.svg | 869 +++++ .../postgres_secret_engine_guide.svg | 864 +++++ .../redis/redis_secret_engine_guide.svg | 1 + .../overview_vault_server_guide.svg | 1 + .../guides/vault-server/vault-login.jpg | Bin 0 -> 22872 bytes .../vault-server/vault_server_guide.svg | 1 + .../v2025.11.21/images/kubevault-overview.svg | 1 + .../images/monitoring/builtin-prom-vault.jpg | Bin 0 -> 33348 bytes .../images/monitoring/coreos-prom-vault.png | Bin 0 -> 32966 bytes .../monitoring/csi-vault-prom-builtin.png | Bin 0 -> 81199 bytes .../monitoring/csi-vault-prom-coreos.png | Bin 0 -> 81676 bytes .../monitoring/grafana-data-source-1.jpg | Bin 0 -> 28848 bytes .../monitoring/grafana-data-source-2.png | Bin 0 -> 74049 bytes .../monitoring/grafana-data-source-3.png | Bin 0 -> 83586 bytes .../images/monitoring/grafana-import-1.png | Bin 0 -> 27678 bytes .../images/monitoring/grafana-import-2.png | Bin 0 -> 68812 bytes .../images/monitoring/grafana-import-3.png | Bin 0 -> 111413 bytes .../images/monitoring/grafana-import-4.png | Bin 0 -> 60008 bytes .../monitoring/vault-operator-builtin.png | Bin 0 -> 33311 bytes .../monitoring/vault-operator-coreos.png | Bin 0 -> 33035 bytes .../images/setup/community_license_form.png | Bin 0 -> 45313 bytes .../images/setup/enterprise_license_form.png | Bin 0 -> 45159 bytes .../v2025.11.21/images/vault-prometheus.jpg | Bin 0 -> 37472 bytes content/docs/v2025.11.21/reference/_index.md | 18 + .../docs/v2025.11.21/reference/cli/_index.md | 18 + .../docs/v2025.11.21/reference/cli/vault.md | 63 + .../reference/cli/vault_approve.md | 63 + .../reference/cli/vault_completion.md | 94 + .../v2025.11.21/reference/cli/vault_deny.md | 63 + .../reference/cli/vault_generate.md | 98 + .../reference/cli/vault_merge-secrets.md | 75 + .../v2025.11.21/reference/cli/vault_revoke.md | 63 + .../reference/cli/vault_root-token.md | 80 + .../reference/cli/vault_root-token_delete.md | 75 + .../cli/vault_root-token_generate.md | 71 + .../reference/cli/vault_root-token_get.md | 78 + .../reference/cli/vault_root-token_rotate.md | 71 + .../reference/cli/vault_root-token_set.md | 76 + .../reference/cli/vault_root-token_sync.md | 72 + .../reference/cli/vault_unseal-key.md | 78 + .../reference/cli/vault_unseal-key_delete.md | 75 + .../reference/cli/vault_unseal-key_get.md | 76 + .../reference/cli/vault_unseal-key_list.md | 70 + .../reference/cli/vault_unseal-key_set.md | 80 + .../reference/cli/vault_unseal-key_sync.md | 72 + .../reference/cli/vault_version.md | 62 + .../v2025.11.21/reference/operator/_index.md | 18 + .../reference/operator/vault-operator.md | 40 + .../operator/vault-operator_operator.md | 58 + .../reference/operator/vault-operator_run.md | 117 + .../operator/vault-operator_version.md | 45 + .../v2025.11.21/reference/unsealer/_index.md | 18 + .../reference/unsealer/vault-unsealer.md | 37 + .../reference/unsealer/vault-unsealer_run.md | 77 + .../unsealer/vault-unsealer_version.md | 43 + content/docs/v2025.11.21/setup/README.md | 42 + content/docs/v2025.11.21/setup/_index.md | 16 + .../docs/v2025.11.21/setup/install/_index.md | 18 + .../setup/install/kubectl_plugin.md | 88 + .../v2025.11.21/setup/install/kubevault.md | 101 + .../setup/install/troubleshoting.md | 51 + .../v2025.11.21/setup/uninstall/_index.md | 18 + .../setup/uninstall/kubectl_plugin.md | 29 + .../v2025.11.21/setup/uninstall/kubevault.md | 57 + .../docs/v2025.11.21/setup/upgrade/index.md | 103 + content/docs/v2025.11.21/support.md | 27 + data/map/world.json | 1 + data/products/kubedb.json | 18 +- data/products/kubedb/databases/hazelcast.json | 82 + data/products/kubeobj.json | 206 + data/products/kubestash.json | 11 +- data/products/kubevault.json | 13 +- data/products/stash-cli.json | 84 +- data/products/stash-elasticsearch.json | 52 +- data/products/stash-etcd.json | 7 +- data/products/stash-kubedump.json | 7 +- data/products/stash-mariadb.json | 7 +- data/products/stash-mongodb.json | 77 +- data/products/stash-mysql.json | 22 +- data/products/stash-nats.json | 12 +- data/products/stash-postgres.json | 47 +- data/products/stash.json | 84 +- .../argo_cd_consulting_support.json | 245 ++ .../build_devops_toolchain.json | 244 ++ .../gitops_consulting.json | 283 ++ .../jenkins_consulting_support.json | 250 ++ .../kubernetes_consulting_partner.json | 253 ++ ...tomotive_cloud_native_devops_services.json | 297 ++ ..._finance_cloud_native_devops_services.json | 292 ++ .../devsecops_consulting_services.json | 271 ++ .../grafana_consulting.json | 251 ++ .../observability_consulting.json | 341 ++ .../prometheus_monitoring_support.json | 261 ++ .../backstage_consulting.json | 246 ++ .../bare_metal_provisioning_consulting.json | 242 ++ .../ci_cd_consulting.json | 350 ++ ...ring_oss_reference_architecture_ebook.json | 62 + .../platform_engineering_services.json | 264 ++ .../progressive_delivery_consulting.json | 351 ++ .../cloud_native_faas.json | 229 ++ .../cloud_native_product_development.json | 380 ++ ...rnetes_comprehensive_guide_whitepaper.json | 116 + .../monolith_to_microservices.json | 185 + data/services/services_menu.json | 220 ++ .../cloud_native_networking_services.json | 270 ++ .../istio_consulting.json | 252 ++ .../kubernetes_disaster_recovery.json | 271 ++ .../service_mesh_consulting.json | 266 ++ .../sre_consulting_services.json | 269 ++ .../terraform_consulting.json | 298 ++ firebase.bk.json | 6 +- firebase.json | 6 +- .../images/databases/logos/hazelcasts.svg | 10 + .../images/databases/logos/png/hazelcasts.png | Bin 0 -> 385 bytes .../assets/images/illustrations/faq-green.png | Bin 0 -> 34367 bytes .../kubeobj/features/data-migration.png | Bin 0 -> 2828 bytes .../features/data-replication-policy.png | Bin 0 -> 720 bytes .../kubeobj/features/high-availability.png | Bin 0 -> 2523 bytes .../kubeobj/features/kubernetes-native.png | Bin 0 -> 3251 bytes .../features/monitoring-and-analytics.png | Bin 0 -> 1236 bytes .../features/multi-cloud-federation.png | Bin 0 -> 3377 bytes .../features/policy-based-data-management.png | Bin 0 -> 1656 bytes .../products/kubeobj/features/scalability.png | Bin 0 -> 1303 bytes .../kubeobj/features/unified-data-access.png | Bin 0 -> 1359 bytes .../products/kubeobj/icons/favicon-32x32.png | Bin 0 -> 978 bytes .../products/kubeobj/icons/favicon-96x96.png | Bin 0 -> 978 bytes .../images/products/kubeobj/icons/favicon.ico | Bin 0 -> 978 bytes .../images/products/kubeobj/icons/kubeobj.png | Bin 0 -> 978 bytes .../images/products/kubeobj/kubeobj.png | Bin 0 -> 13364 bytes .../images/products/kubeobj/kubeobj.svg | 17 + .../images/products/others/logos/perses.svg | 75 + static/assets/images/services/analytics.png | Bin 0 -> 87893 bytes ...o-cd-consulting-implementation-service.png | Bin 0 -> 127848 bytes .../argo-cd-consulting-implementation.png | Bin 0 -> 103533 bytes .../services/argo-cd-gitops-service.png | Bin 0 -> 111036 bytes .../argo-cd-multi-tenancy-service.png | Bin 0 -> 78785 bytes .../argo-cd-training-support-service.png | Bin 0 -> 68459 bytes .../images/services/automotive-industry.png | Bin 0 -> 148238 bytes .../images/services/autonomous-vehicles.png | Bin 0 -> 179966 bytes ...stage-consulting-and-adoption-strategy.png | Bin 0 -> 203988 bytes .../services/backstage-consulting-hero.png | Bin 0 -> 134278 bytes .../backstage-support-and-training.png | Bin 0 -> 199996 bytes ...g-finance-cloud-native-devops-services.png | Bin 0 -> 108523 bytes ...are-metal-provisioning-consulting-hero.png | Bin 0 -> 192675 bytes ...d-future-ready-platforms-with-appscode.png | Bin 0 -> 91103 bytes static/assets/images/services/cbdc.png | Bin 0 -> 123279 bytes .../images/services/ci-cd-automation.png | Bin 0 -> 97429 bytes .../services/ci-cd-consulting-consulting.png | Bin 0 -> 121058 bytes .../services/ci-cd-consulting-design.png | Bin 0 -> 71890 bytes .../ci-cd-consulting-implementation.png | Bin 0 -> 146604 bytes .../services/ci-cd-consulting-training.png | Bin 0 -> 173948 bytes .../images/services/ci-cd-consulting.png | Bin 0 -> 116138 bytes .../images/services/cloud-migration.png | Bin 0 -> 114120 bytes .../cloud-native-networking-services.png | Bin 0 -> 78435 bytes .../images/services/connected-vehicles.png | Bin 0 -> 168906 bytes .../images/services/consulting-advisory.png | Bin 0 -> 95083 bytes .../services/customer-experience-services.png | Bin 0 -> 93075 bytes ...ustomized-os-building-and-verification.png | Bin 0 -> 113785 bytes .../devops-toolchain-consulting-hero.png | Bin 0 -> 104322 bytes .../images/services/devsecops-assessment.png | Bin 0 -> 169885 bytes .../devsecops-compliance-audit-readiness.png | Bin 0 -> 137333 bytes .../devsecops-consulting-advisory.png | Bin 0 -> 142423 bytes .../images/services/devsecops-consulting.png | Bin 0 -> 149924 bytes .../devsecops-enablement-training.png | Bin 0 -> 114518 bytes .../devsecops-security-tool-deployment.png | Bin 0 -> 126431 bytes .../images/services/digital-manufacturing.png | Bin 0 -> 95639 bytes .../images/services/digital-payments.png | Bin 0 -> 145637 bytes .../services/enterprise-support-services.png | Bin 0 -> 132986 bytes .../services/enterprise-support-training.png | Bin 0 -> 137742 bytes ...ernetes-comprehensive-guide-whitepaper.png | Bin 0 -> 137650 bytes .../services/fintech-financial-isvs.png | Bin 0 -> 141198 bytes .../gitops-consulting-implementation-hero.png | Bin 0 -> 64359 bytes ...itops-implementation-dev-to-production.png | Bin 0 -> 89854 bytes .../images/services/gitops-tools-training.png | Bin 0 -> 89917 bytes .../images/services/grafana-alerting.png | Bin 0 -> 90608 bytes .../grafana-consulting-illustration.png | Bin 0 -> 100163 bytes .../services/grafana-data-integration.png | Bin 0 -> 71987 bytes .../images/services/grafana-reporting.png | Bin 0 -> 112882 bytes .../grafana-strategy-implementation.png | Bin 0 -> 141651 bytes .../assets/images/services/iac-management.png | Bin 0 -> 110266 bytes .../implement-production-grade-backstage.png | Bin 0 -> 108623 bytes .../services/integration-deployment.png | Bin 0 -> 78722 bytes .../integration-with-tools-and-workflows.png | Bin 0 -> 114759 bytes .../services/integrations-ecosystem-setup.png | Bin 0 -> 87718 bytes .../services/istio-consulting-advisory.png | Bin 0 -> 105630 bytes .../images/services/istio-consulting-hero.png | Bin 0 -> 126904 bytes .../istio-consulting-implementation.png | Bin 0 -> 91520 bytes .../services/istio-consulting-security.png | Bin 0 -> 100702 bytes .../jenkins-consulting-best-practices.png | Bin 0 -> 67290 bytes .../jenkins-consulting-delivery-time.png | Bin 0 -> 99306 bytes .../jenkins-consulting-dev-lifecycle.png | Bin 0 -> 100674 bytes .../services/jenkins-consulting-devops.png | Bin 0 -> 127126 bytes .../jenkins-consulting-enterprise-support.png | Bin 0 -> 128982 bytes .../jenkins-consulting-training-support.png | Bin 0 -> 179349 bytes .../images/services/kubernetes-advisory.png | Bin 0 -> 250891 bytes .../kubernetes-application-development.png | Bin 0 -> 142430 bytes .../kubernetes-backup-data-protection.png | Bin 0 -> 99734 bytes .../kubernetes-business-continuity.png | Bin 0 -> 111541 bytes .../images/services/kubernetes-consulting.png | Bin 0 -> 97268 bytes .../services/kubernetes-consultings.png | Bin 0 -> 115339 bytes .../kubernetes-deployment-partner.png | Bin 0 -> 261488 bytes .../kubernetes-devsecops-compliance.png | Bin 0 -> 327452 bytes .../kubernetes-disaster-recovery-2.png | Bin 0 -> 186260 bytes .../services/kubernetes-disaster-recovery.png | Bin 0 -> 79278 bytes ...kubernetes-enterprise-support-training.png | Bin 0 -> 131303 bytes .../images/services/kubernetes-migration.png | Bin 0 -> 89638 bytes .../services/kubernetes-multi-cloud.png | Bin 0 -> 85401 bytes .../services/managed-devops-services.png | Bin 0 -> 132480 bytes .../services/managed-devsecops-services.png | Bin 0 -> 106828 bytes .../managed-services-continuous-support.png | Bin 0 -> 133286 bytes .../microservices-consulting-strategy.png | Bin 0 -> 198977 bytes ...croservices-integration-api-management.png | Bin 0 -> 72689 bytes ...rvices-support-monitoring-optimization.png | Bin 0 -> 110952 bytes ...olith-microservices-modernization-hero.png | Bin 0 -> 224626 bytes .../monolith-to-microservices-migration.png | Bin 0 -> 188568 bytes ...p-strategy-platform-roadmap-consulting.png | Bin 0 -> 111890 bytes .../network-assessment-optimization.png | Bin 0 -> 93539 bytes .../network-automation-policy-management.png | Bin 0 -> 92797 bytes .../observability-consulting-hero.png | Bin 0 -> 97466 bytes .../observability-distributed-tracing.png | Bin 0 -> 89096 bytes ...bservability-infrastructure-monitoring.png | Bin 0 -> 123938 bytes .../observability-traffic-management.png | Bin 0 -> 103389 bytes .../observability-unified-logging.png | Bin 0 -> 100832 bytes .../on-prem-hardware-to-maas-guidance.png | Bin 0 -> 121733 bytes .../on-prem-kubernetes-provisioning.png | Bin 0 -> 120470 bytes static/assets/images/services/open-source.png | Bin 0 -> 356353 bytes .../services/platform-design-development.png | Bin 0 -> 96339 bytes .../platform-engineering-ebook-inside.png | Bin 0 -> 141668 bytes .../services/platform-engineering-ebook.png | Bin 0 -> 149516 bytes ...atform-engineering-training-enablement.png | Bin 0 -> 116968 bytes .../services/platform-support-maintenance.png | Bin 0 -> 152365 bytes .../process-design-implementation.png | Bin 0 -> 109211 bytes ...-cloud-native-product-development-hero.png | Bin 0 -> 187177 bytes .../product-market-fit-assessment.png | Bin 0 -> 101554 bytes ...ogressive-delivery-consulting-advisory.png | Bin 0 -> 72502 bytes ...ive-delivery-consulting-implementation.png | Bin 0 -> 134961 bytes ...rogressive-delivery-consulting-support.png | Bin 0 -> 133015 bytes ...ogressive-delivery-consulting-training.png | Bin 0 -> 78310 bytes .../progressive-delivery-consulting.png | Bin 0 -> 138563 bytes ...prometheus-commercial-support-training.png | Bin 0 -> 192686 bytes .../prometheus-consulting-implementation.png | Bin 0 -> 99806 bytes .../prometheus-data-modeling-querying.png | Bin 0 -> 72319 bytes .../prometheus-incident-management.png | Bin 0 -> 132280 bytes .../prometheus-monitoring-support.png | Bin 0 -> 144413 bytes .../prometheus-third-party-integration.png | Bin 0 -> 112688 bytes .../services/retail-corporate-banking.png | Bin 0 -> 177869 bytes .../images/services/scalability-planning.png | Bin 0 -> 74786 bytes .../images/services/scalable-growth.png | Bin 0 -> 58673 bytes .../security-and-compliance-integration.png | Bin 0 -> 104703 bytes .../images/services/security-compliance.png | Bin 0 -> 91343 bytes .../services/serverless-consulting-hero.png | Bin 0 -> 80080 bytes .../serverless-implementation-services.png | Bin 0 -> 67031 bytes .../images/services/serverless-operations.png | Bin 0 -> 105148 bytes .../services/serverless-strategy-advisory.png | Bin 0 -> 187889 bytes .../service-mesh-consulting-advisory.png | Bin 0 -> 140944 bytes .../service-mesh-consulting-deployment.png | Bin 0 -> 105402 bytes .../service-mesh-consulting-integration.png | Bin 0 -> 91324 bytes .../service-mesh-consulting-support.png | Bin 0 -> 71421 bytes .../services/service-mesh-consulting.png | Bin 0 -> 128321 bytes .../sre-consulting-disaster-recovery.png | Bin 0 -> 169110 bytes .../sre-consulting-incident-management.png | Bin 0 -> 86087 bytes ...e-consulting-infrastructure-management.png | Bin 0 -> 168371 bytes .../services/sre-consulting-observability.png | Bin 0 -> 130348 bytes .../sre-consulting-security-governance.png | Bin 0 -> 156150 bytes .../services/sre-consulting-services.png | Bin 0 -> 120773 bytes .../services/sre-consulting-strategy.png | Bin 0 -> 123433 bytes .../services/sre-consulting-training.png | Bin 0 -> 133709 bytes .../images/services/steps/build-mvp.png | Bin 0 -> 657023 bytes .../images/services/steps/development.png | Bin 0 -> 350273 bytes .../services/steps/discover-opportunities.png | Bin 0 -> 453782 bytes .../assets/images/services/steps/launch.png | Bin 0 -> 348352 bytes static/assets/images/services/steps/scale.png | Bin 0 -> 486369 bytes ...rategic-consulting-architecture-design.png | Bin 0 -> 126400 bytes .../services/terraform-cloud-enterprise.png | Bin 0 -> 86993 bytes .../images/services/terraform-consulting.png | Bin 0 -> 178876 bytes static/assets/images/services/terragrunt.png | Bin 0 -> 98538 bytes .../tinkerbell-enterprise-support.png | Bin 0 -> 85826 bytes .../images/services/toolchain-analysis.png | Bin 0 -> 84908 bytes .../images/services/toolchain-training.png | Bin 0 -> 135161 bytes .../images/services/training-enablement.png | Bin 0 -> 109570 bytes .../services/upskilling-team-enablement.png | Bin 0 -> 155668 bytes .../images/services/why-should-read-paper.png | Bin 0 -> 144677 bytes .../images/technical-expertise/argocd.svg | 1 + .../images/technical-expertise/crossplane.svg | 35 + .../images/technical-expertise/fluxcd.svg | 39 + .../images/technical-expertise/grafana.svg | 1 + .../images/technical-expertise/graphql.svg | 2 + .../images/technical-expertise/helm.svg | 1 + .../images/technical-expertise/kasten.svg | 1 + .../images/technical-expertise/kubernetes.svg | 1 + .../images/technical-expertise/kustomize.png | Bin 0 -> 2674 bytes .../technical-expertise/open-policy-agent.png | Bin 0 -> 35346 bytes .../images/technical-expertise/prometheus.svg | 1 + .../images/technical-expertise/terraform.svg | 1 + .../images/technical-expertise/terragrunt.png | Bin 0 -> 15920 bytes .../images/technical-expertise/thanos.svg | 1 + .../images/technical-expertise/werf.svg | 3 + .../iam-credential-manager-permissions.json | 10 + .../aws-selfhost/iam-ec2-permissions.json | 206 + .../aws-selfhost/iam-eks-permissions.json | 155 + .../aws-selfhost/iam-stash-permissions.json | 25 + .../aws-selfhost/template-trust-relationship | 18 + 675 files changed, 52812 insertions(+), 19 deletions(-) create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2021.08.02.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2021.09.27.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2021.10.11.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2022.01.11.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2022.02.22.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2022.06.16.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2022.09.05-rc.0.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2022.09.09.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2022.09.22.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2022.11.30.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2022.12.09.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2022.12.28.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2023.03.03.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2023.05.05.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2023.9.7.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2024.1.26-rc.0.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2024.1.28-rc.1.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2024.1.31.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2024.3.12.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2024.9.30.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2025.11.21.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2025.2.10.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2025.2.6-rc.0.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2025.5.26.md create mode 100644 content/docs/v2025.11.21/CHANGELOG-v2025.5.30.md create mode 100644 content/docs/v2025.11.21/CONTRIBUTING.md create mode 100644 content/docs/v2025.11.21/README.md create mode 100644 content/docs/v2025.11.21/_index.md create mode 100644 content/docs/v2025.11.21/concepts/README.md create mode 100755 content/docs/v2025.11.21/concepts/_index.md create mode 100644 content/docs/v2025.11.21/concepts/architecture.md create mode 100644 content/docs/v2025.11.21/concepts/backup-restore/_index.md create mode 100644 content/docs/v2025.11.21/concepts/backup-restore/overview.md create mode 100644 content/docs/v2025.11.21/concepts/overview.md create mode 100755 content/docs/v2025.11.21/concepts/policy-crds/_index.md create mode 100644 content/docs/v2025.11.21/concepts/policy-crds/vaultpolicy.md create mode 100644 content/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding.md create mode 100755 content/docs/v2025.11.21/concepts/secret-engine-crds/_index.md create mode 100755 content/docs/v2025.11.21/concepts/secret-engine-crds/aws-secret-engine/_index.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/aws-secret-engine/awsrole.md create mode 100755 content/docs/v2025.11.21/concepts/secret-engine-crds/azure-secret-engine/_index.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/azure-secret-engine/azurerole.md create mode 100755 content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/_index.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/elasticsearch.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mariadb.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mongodb.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mysql.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/postgresrole.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/redis.md create mode 100755 content/docs/v2025.11.21/concepts/secret-engine-crds/gcp-secret-engine/_index.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/gcp-secret-engine/gcprole.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/pki-secret-engine/_index.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/pki-secret-engine/pkirole.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/secret-access-request.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/secret-role-binding.md create mode 100644 content/docs/v2025.11.21/concepts/secret-engine-crds/secretengine.md create mode 100644 content/docs/v2025.11.21/concepts/tls-encryption/_index.md create mode 100644 content/docs/v2025.11.21/concepts/tls-encryption/configuration.md create mode 100644 content/docs/v2025.11.21/concepts/tls-encryption/overview.md create mode 100644 content/docs/v2025.11.21/concepts/vault-ops-request/_index.md create mode 100644 content/docs/v2025.11.21/concepts/vault-ops-request/overview.md create mode 100755 content/docs/v2025.11.21/concepts/vault-server-crds/_index.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/appbinding.md create mode 100755 content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/_index.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/aws-iam.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/azure.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/gcp-iam.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/jwt-oidc.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/kubernetes.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/overview.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/tls.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/token.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/userpass.md create mode 100755 content/docs/v2025.11.21/concepts/vault-server-crds/storage/_index.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/azure.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/consul.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/dynamodb.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/etcd.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/filesystem.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/gcs.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/inmem.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/mysql.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/overview.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/postgresql.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/raft.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/s3.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/storage/swift.md create mode 100755 content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/_index.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/aws_kms_ssm.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/azure_key_vault.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/google_kms_gcs.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/kubernetes_secret.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/overview.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/vaultserver.md create mode 100644 content/docs/v2025.11.21/concepts/vault-server-crds/vaultserverversion.md create mode 100644 content/docs/v2025.11.21/examples/guides/backup-restore/backup-configuration.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/backup-restore/repository.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/backup-restore/restore-session.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/backup-restore/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/policy-management/policy-reader-role.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/policy-management/read-only-policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/policy-management/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/policy-management/vaultserverversion.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/aks/my-vault.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/aks/vaultserverversion.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/eks/my-vault.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/external-vault/demo-policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/external-vault/policy-admin-sa.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/external-vault/policy-admin.hcl create mode 100644 content/docs/v2025.11.21/examples/guides/provider/external-vault/token-review-binding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/external-vault/token-reviewer-sa.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/external-vault/vault-app.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/external-vault/vault.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/gke/my-vault.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/gke/vaultserverversion.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/multi-cluster/demo-policy-secret-admin.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/multi-cluster/demo-policy-secret-reader.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/multi-cluster/my-vault.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/multi-cluster/vault-app.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/multi-cluster/vault-token.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/provider/multi-cluster/vaultserverversion.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/aws/pod.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/aws/policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/aws/policybinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/aws/secret-role-binding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/aws/secret.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/aws/secretengine.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/aws/secretenginerole.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/aws/secretproviderclass.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/aws/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/aws/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/azure/pod.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/azure/policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/azure/policybinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/azure/secret-role-binding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/azure/secret.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/azure/secretengine.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/azure/secretenginerole.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/azure/secretproviderclass.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/azure/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/azure/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/elasticsearch.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/pod.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/policybinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secret-role-binding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secretengine.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secretenginerole.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secretproviderclass.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/gcp/pod.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/gcp/policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/gcp/policybinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secret-role-binding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secret.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secretengine.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secretenginerole.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secretproviderclass.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/gcp/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/gcp/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/kv/pod.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/kv/policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/kv/policybinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/kv/secretproviderclass.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/kv/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/kv/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/mariadb.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/pod.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/policybinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secret-role-binding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secretengine.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secretenginerole.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secretproviderclass.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/mongodb.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/pod.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/policybinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretengine.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretenginerole.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretproviderclass.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretrolebinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mysql/mysql.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mysql/pod.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mysql/policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mysql/policybinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secret-role-binding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secretengine.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secretenginerole.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secretproviderclass.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mysql/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/mysql/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/pki/pod.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/pki/policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/pki/policybinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/pki/secretproviderclass.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/pki/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/pki/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/postgres/pod.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/postgres/policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/postgres/policybinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/postgres/postgres.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretengine.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretenginerole.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretproviderclass.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretrolebinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/postgres/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/postgres/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/redis/pod.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/redis/redis.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/redis/redisaccessrequest.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/redis/secret-role-binding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/redis/secretengine.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/redis/secretenginerole.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/redis/secretproviderclass.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/redis/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/redis/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secret.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secretaccessrequest.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secretengine.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secretenginerole.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secret.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secretengine.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secretenginerole.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secretrolebinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/serviceaccount.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/vault-ops-request/issuer.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/vault-ops-request/new-issuer.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-add-tls.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-change-issuer.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-remove.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-rotate.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/vault-ops-request/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/vault-server/appBinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/vault-server/ca.crt create mode 100644 content/docs/v2025.11.21/examples/guides/vault-server/clusterRoleBinding.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/vault-server/secret-policy.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/vault-server/vault.hcl create mode 100644 content/docs/v2025.11.21/examples/guides/vault-server/vaultserver.yaml create mode 100644 content/docs/v2025.11.21/examples/guides/vault-server/vaultserverversion.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/csi-driver/prom-builtin-conf.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/csi-driver/prom-builtin-deployment.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/csi-driver/prom-coreos-crd.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/grafana/dashboard.json create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-operator/prom-builtin-deployment.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-operator/prom-coreos-crd.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-operator/prom-server-conf.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-builtin.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-coreos-operator.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-coreos.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-service.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-operator/vault-server-builtin.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-operator/vault-server-coreos.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-server/prom-server-conf.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-builtin.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-coreos-operator.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-coreos.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-service.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-server/vault-server-builtin.yaml create mode 100644 content/docs/v2025.11.21/examples/monitoring/vault-server/vault-server-coreos.yaml create mode 100644 content/docs/v2025.11.21/examples/vaultserver_inmem_k8s_unsealer.yaml create mode 100644 content/docs/v2025.11.21/guides/README.md create mode 100755 content/docs/v2025.11.21/guides/_index.md create mode 100644 content/docs/v2025.11.21/guides/backup-restore/_index.md create mode 100644 content/docs/v2025.11.21/guides/backup-restore/backup.md create mode 100644 content/docs/v2025.11.21/guides/backup-restore/overview.md create mode 100644 content/docs/v2025.11.21/guides/backup-restore/restore.md create mode 100644 content/docs/v2025.11.21/guides/monitoring/_index.md create mode 100644 content/docs/v2025.11.21/guides/monitoring/overview.md create mode 100755 content/docs/v2025.11.21/guides/monitoring/vault-operator/_index.md create mode 100644 content/docs/v2025.11.21/guides/monitoring/vault-operator/builtin.md create mode 100644 content/docs/v2025.11.21/guides/monitoring/vault-operator/coreos.md create mode 100755 content/docs/v2025.11.21/guides/monitoring/vault-server/_index.md create mode 100644 content/docs/v2025.11.21/guides/monitoring/vault-server/builtin.md create mode 100644 content/docs/v2025.11.21/guides/monitoring/vault-server/coreos.md create mode 100644 content/docs/v2025.11.21/guides/monitoring/vault-server/grafana.md create mode 100755 content/docs/v2025.11.21/guides/platforms/_index.md create mode 100644 content/docs/v2025.11.21/guides/platforms/aks.md create mode 100644 content/docs/v2025.11.21/guides/platforms/eks.md create mode 100644 content/docs/v2025.11.21/guides/platforms/external-vault.md create mode 100644 content/docs/v2025.11.21/guides/platforms/gke.md create mode 100644 content/docs/v2025.11.21/guides/platforms/multi-cluster-vault.md create mode 100755 content/docs/v2025.11.21/guides/policy-management/_index.md create mode 100644 content/docs/v2025.11.21/guides/policy-management/overview.md create mode 100755 content/docs/v2025.11.21/guides/secret-engines/_index.md create mode 100755 content/docs/v2025.11.21/guides/secret-engines/aws/_index.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/aws/csi-driver.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/aws/overview.md create mode 100755 content/docs/v2025.11.21/guides/secret-engines/azure/_index.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/azure/csi-driver.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/azure/overview.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg create mode 100755 content/docs/v2025.11.21/guides/secret-engines/elasticsearch/_index.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/elasticsearch/csi-driver.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/elasticsearch/overview.md create mode 100755 content/docs/v2025.11.21/guides/secret-engines/gcp/_index.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/gcp/csi-driver.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/gcp/overview.md create mode 100755 content/docs/v2025.11.21/guides/secret-engines/kv/_index.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/kv/csi-driver.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/kv/overview.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/mariadb/_index.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/mariadb/csi-driver.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/mariadb/overview.md create mode 100755 content/docs/v2025.11.21/guides/secret-engines/mongodb/_index.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/mongodb/csi-driver.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/mongodb/overview.md create mode 100755 content/docs/v2025.11.21/guides/secret-engines/mysql/_index.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/mysql/csi-driver.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/mysql/overview.md create mode 100755 content/docs/v2025.11.21/guides/secret-engines/pki/_index.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/pki/csi-driver.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/pki/overview.md create mode 100755 content/docs/v2025.11.21/guides/secret-engines/postgres/_index.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/postgres/csi-driver.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/postgres/overview.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/redis/_index.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/redis/csi-driver.md create mode 100644 content/docs/v2025.11.21/guides/secret-engines/redis/overview.md create mode 100644 content/docs/v2025.11.21/guides/vault-ops-request/_index.md create mode 100644 content/docs/v2025.11.21/guides/vault-ops-request/overview.md create mode 100644 content/docs/v2025.11.21/guides/vault-ops-request/reconfigure_tls.md create mode 100755 content/docs/v2025.11.21/guides/vault-server/_index.md create mode 100644 content/docs/v2025.11.21/guides/vault-server/auth-method.md create mode 100644 content/docs/v2025.11.21/guides/vault-server/external-vault-sever.md create mode 100644 content/docs/v2025.11.21/guides/vault-server/overview.md create mode 100644 content/docs/v2025.11.21/guides/vault-server/vault-server.md create mode 100644 content/docs/v2025.11.21/images/concepts/architecture.svg create mode 100644 content/docs/v2025.11.21/images/concepts/aws_role.svg create mode 100644 content/docs/v2025.11.21/images/concepts/azure_role.svg create mode 100644 content/docs/v2025.11.21/images/concepts/backup.svg create mode 100644 content/docs/v2025.11.21/images/concepts/elasticsearch_role.svg create mode 100644 content/docs/v2025.11.21/images/concepts/gcp_role.svg create mode 100644 content/docs/v2025.11.21/images/concepts/mariadb_role.svg create mode 100644 content/docs/v2025.11.21/images/concepts/mongodb_role.svg create mode 100644 content/docs/v2025.11.21/images/concepts/mysql_role.svg create mode 100644 content/docs/v2025.11.21/images/concepts/pki_role.svg create mode 100644 content/docs/v2025.11.21/images/concepts/postgres_role.svg create mode 100644 content/docs/v2025.11.21/images/concepts/redis_role.svg create mode 100644 content/docs/v2025.11.21/images/concepts/restore.svg create mode 100644 content/docs/v2025.11.21/images/concepts/secret_access_request.svg create mode 100644 content/docs/v2025.11.21/images/concepts/vault_policy.svg create mode 100644 content/docs/v2025.11.21/images/concepts/vault_policy_binding.svg create mode 100644 content/docs/v2025.11.21/images/concepts/vault_server.svg create mode 100644 content/docs/v2025.11.21/images/csi-driver-policy-aws.jpg create mode 100644 content/docs/v2025.11.21/images/guides/backup-restore/backup.png create mode 100644 content/docs/v2025.11.21/images/guides/policy-management/vault_policy.svg create mode 100644 content/docs/v2025.11.21/images/guides/policy-management/vault_policy_binding.svg create mode 100644 content/docs/v2025.11.21/images/guides/provider/aks/aks.png create mode 100644 content/docs/v2025.11.21/images/guides/provider/aks/key-vault.png create mode 100644 content/docs/v2025.11.21/images/guides/provider/aks/root-token.png create mode 100644 content/docs/v2025.11.21/images/guides/provider/aks/secret-access.png create mode 100644 content/docs/v2025.11.21/images/guides/provider/aks/unseal-keys.png create mode 100644 content/docs/v2025.11.21/images/guides/provider/eks/aws-instance.png create mode 100644 content/docs/v2025.11.21/images/guides/provider/eks/unseal-keys.png create mode 100644 content/docs/v2025.11.21/images/guides/provider/gke/gke-cluster.png create mode 100644 content/docs/v2025.11.21/images/guides/provider/gke/gke-unseal-keys.png create mode 100644 content/docs/v2025.11.21/images/guides/provider/multi-cluster/gke-cluster.png create mode 100644 content/docs/v2025.11.21/images/guides/secret-engines/aws/aws_secret_engine_guide.svg create mode 100644 content/docs/v2025.11.21/images/guides/secret-engines/azure/azure_secret_engine_guide.svg create mode 100644 content/docs/v2025.11.21/images/guides/secret-engines/elasticsearch/elasticsearch_secret_engine_guide.svg create mode 100644 content/docs/v2025.11.21/images/guides/secret-engines/gcp/gcp_guide.svg create mode 100644 content/docs/v2025.11.21/images/guides/secret-engines/mariadb/mariadb_secret_engine_guide.svg create mode 100644 content/docs/v2025.11.21/images/guides/secret-engines/mongodb/mongodb_secret_engine_guide.svg create mode 100644 content/docs/v2025.11.21/images/guides/secret-engines/mysql/mysql_secret_engine_guide.svg create mode 100644 content/docs/v2025.11.21/images/guides/secret-engines/postgresql/postgres_secret_engine_guide.svg create mode 100644 content/docs/v2025.11.21/images/guides/secret-engines/redis/redis_secret_engine_guide.svg create mode 100644 content/docs/v2025.11.21/images/guides/vault-server/overview_vault_server_guide.svg create mode 100644 content/docs/v2025.11.21/images/guides/vault-server/vault-login.jpg create mode 100644 content/docs/v2025.11.21/images/guides/vault-server/vault_server_guide.svg create mode 100644 content/docs/v2025.11.21/images/kubevault-overview.svg create mode 100644 content/docs/v2025.11.21/images/monitoring/builtin-prom-vault.jpg create mode 100644 content/docs/v2025.11.21/images/monitoring/coreos-prom-vault.png create mode 100644 content/docs/v2025.11.21/images/monitoring/csi-vault-prom-builtin.png create mode 100644 content/docs/v2025.11.21/images/monitoring/csi-vault-prom-coreos.png create mode 100644 content/docs/v2025.11.21/images/monitoring/grafana-data-source-1.jpg create mode 100644 content/docs/v2025.11.21/images/monitoring/grafana-data-source-2.png create mode 100644 content/docs/v2025.11.21/images/monitoring/grafana-data-source-3.png create mode 100644 content/docs/v2025.11.21/images/monitoring/grafana-import-1.png create mode 100644 content/docs/v2025.11.21/images/monitoring/grafana-import-2.png create mode 100644 content/docs/v2025.11.21/images/monitoring/grafana-import-3.png create mode 100644 content/docs/v2025.11.21/images/monitoring/grafana-import-4.png create mode 100644 content/docs/v2025.11.21/images/monitoring/vault-operator-builtin.png create mode 100644 content/docs/v2025.11.21/images/monitoring/vault-operator-coreos.png create mode 100644 content/docs/v2025.11.21/images/setup/community_license_form.png create mode 100644 content/docs/v2025.11.21/images/setup/enterprise_license_form.png create mode 100644 content/docs/v2025.11.21/images/vault-prometheus.jpg create mode 100644 content/docs/v2025.11.21/reference/_index.md create mode 100644 content/docs/v2025.11.21/reference/cli/_index.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_approve.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_completion.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_deny.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_generate.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_merge-secrets.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_revoke.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_root-token.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_root-token_delete.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_root-token_generate.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_root-token_get.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_root-token_rotate.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_root-token_set.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_root-token_sync.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_unseal-key.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_unseal-key_delete.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_unseal-key_get.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_unseal-key_list.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_unseal-key_set.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_unseal-key_sync.md create mode 100644 content/docs/v2025.11.21/reference/cli/vault_version.md create mode 100644 content/docs/v2025.11.21/reference/operator/_index.md create mode 100644 content/docs/v2025.11.21/reference/operator/vault-operator.md create mode 100644 content/docs/v2025.11.21/reference/operator/vault-operator_operator.md create mode 100644 content/docs/v2025.11.21/reference/operator/vault-operator_run.md create mode 100644 content/docs/v2025.11.21/reference/operator/vault-operator_version.md create mode 100644 content/docs/v2025.11.21/reference/unsealer/_index.md create mode 100644 content/docs/v2025.11.21/reference/unsealer/vault-unsealer.md create mode 100644 content/docs/v2025.11.21/reference/unsealer/vault-unsealer_run.md create mode 100644 content/docs/v2025.11.21/reference/unsealer/vault-unsealer_version.md create mode 100644 content/docs/v2025.11.21/setup/README.md create mode 100644 content/docs/v2025.11.21/setup/_index.md create mode 100644 content/docs/v2025.11.21/setup/install/_index.md create mode 100644 content/docs/v2025.11.21/setup/install/kubectl_plugin.md create mode 100644 content/docs/v2025.11.21/setup/install/kubevault.md create mode 100644 content/docs/v2025.11.21/setup/install/troubleshoting.md create mode 100644 content/docs/v2025.11.21/setup/uninstall/_index.md create mode 100644 content/docs/v2025.11.21/setup/uninstall/kubectl_plugin.md create mode 100644 content/docs/v2025.11.21/setup/uninstall/kubevault.md create mode 100644 content/docs/v2025.11.21/setup/upgrade/index.md create mode 100644 content/docs/v2025.11.21/support.md create mode 100644 data/map/world.json create mode 100644 data/products/kubedb/databases/hazelcast.json create mode 100644 data/products/kubeobj.json create mode 100644 data/services/application-modernization/argo_cd_consulting_support.json create mode 100644 data/services/application-modernization/build_devops_toolchain.json create mode 100644 data/services/application-modernization/gitops_consulting.json create mode 100644 data/services/application-modernization/jenkins_consulting_support.json create mode 100644 data/services/application-modernization/kubernetes_consulting_partner.json create mode 100644 data/services/industries/automotive_cloud_native_devops_services.json create mode 100644 data/services/industries/banking_finance_cloud_native_devops_services.json create mode 100644 data/services/observability-devsecops/devsecops_consulting_services.json create mode 100644 data/services/observability-devsecops/grafana_consulting.json create mode 100644 data/services/observability-devsecops/observability_consulting.json create mode 100644 data/services/observability-devsecops/prometheus_monitoring_support.json create mode 100644 data/services/platform-engineering/backstage_consulting.json create mode 100644 data/services/platform-engineering/bare_metal_provisioning_consulting.json create mode 100644 data/services/platform-engineering/ci_cd_consulting.json create mode 100644 data/services/platform-engineering/platform_engineering_oss_reference_architecture_ebook.json create mode 100644 data/services/platform-engineering/platform_engineering_services.json create mode 100644 data/services/platform-engineering/progressive_delivery_consulting.json create mode 100644 data/services/product-engineering/cloud_native_faas.json create mode 100644 data/services/product-engineering/cloud_native_product_development.json create mode 100644 data/services/product-engineering/extending_kubernetes_comprehensive_guide_whitepaper.json create mode 100644 data/services/product-engineering/monolith_to_microservices.json create mode 100644 data/services/services_menu.json create mode 100644 data/services/site-reliability-engineering/cloud_native_networking_services.json create mode 100644 data/services/site-reliability-engineering/istio_consulting.json create mode 100644 data/services/site-reliability-engineering/kubernetes_disaster_recovery.json create mode 100644 data/services/site-reliability-engineering/service_mesh_consulting.json create mode 100644 data/services/site-reliability-engineering/sre_consulting_services.json create mode 100644 data/services/site-reliability-engineering/terraform_consulting.json create mode 100644 static/assets/images/databases/logos/hazelcasts.svg create mode 100644 static/assets/images/databases/logos/png/hazelcasts.png create mode 100644 static/assets/images/illustrations/faq-green.png create mode 100644 static/assets/images/products/kubeobj/features/data-migration.png create mode 100644 static/assets/images/products/kubeobj/features/data-replication-policy.png create mode 100644 static/assets/images/products/kubeobj/features/high-availability.png create mode 100644 static/assets/images/products/kubeobj/features/kubernetes-native.png create mode 100644 static/assets/images/products/kubeobj/features/monitoring-and-analytics.png create mode 100644 static/assets/images/products/kubeobj/features/multi-cloud-federation.png create mode 100644 static/assets/images/products/kubeobj/features/policy-based-data-management.png create mode 100644 static/assets/images/products/kubeobj/features/scalability.png create mode 100644 static/assets/images/products/kubeobj/features/unified-data-access.png create mode 100644 static/assets/images/products/kubeobj/icons/favicon-32x32.png create mode 100644 static/assets/images/products/kubeobj/icons/favicon-96x96.png create mode 100644 static/assets/images/products/kubeobj/icons/favicon.ico create mode 100644 static/assets/images/products/kubeobj/icons/kubeobj.png create mode 100644 static/assets/images/products/kubeobj/kubeobj.png create mode 100644 static/assets/images/products/kubeobj/kubeobj.svg create mode 100644 static/assets/images/products/others/logos/perses.svg create mode 100644 static/assets/images/services/analytics.png create mode 100644 static/assets/images/services/argo-cd-consulting-implementation-service.png create mode 100644 static/assets/images/services/argo-cd-consulting-implementation.png create mode 100644 static/assets/images/services/argo-cd-gitops-service.png create mode 100644 static/assets/images/services/argo-cd-multi-tenancy-service.png create mode 100644 static/assets/images/services/argo-cd-training-support-service.png create mode 100644 static/assets/images/services/automotive-industry.png create mode 100644 static/assets/images/services/autonomous-vehicles.png create mode 100644 static/assets/images/services/backstage-consulting-and-adoption-strategy.png create mode 100644 static/assets/images/services/backstage-consulting-hero.png create mode 100644 static/assets/images/services/backstage-support-and-training.png create mode 100644 static/assets/images/services/banking-finance-cloud-native-devops-services.png create mode 100644 static/assets/images/services/bare-metal-provisioning-consulting-hero.png create mode 100644 static/assets/images/services/build-future-ready-platforms-with-appscode.png create mode 100644 static/assets/images/services/cbdc.png create mode 100644 static/assets/images/services/ci-cd-automation.png create mode 100644 static/assets/images/services/ci-cd-consulting-consulting.png create mode 100644 static/assets/images/services/ci-cd-consulting-design.png create mode 100644 static/assets/images/services/ci-cd-consulting-implementation.png create mode 100644 static/assets/images/services/ci-cd-consulting-training.png create mode 100644 static/assets/images/services/ci-cd-consulting.png create mode 100644 static/assets/images/services/cloud-migration.png create mode 100644 static/assets/images/services/cloud-native-networking-services.png create mode 100644 static/assets/images/services/connected-vehicles.png create mode 100644 static/assets/images/services/consulting-advisory.png create mode 100644 static/assets/images/services/customer-experience-services.png create mode 100644 static/assets/images/services/customized-os-building-and-verification.png create mode 100644 static/assets/images/services/devops-toolchain-consulting-hero.png create mode 100644 static/assets/images/services/devsecops-assessment.png create mode 100644 static/assets/images/services/devsecops-compliance-audit-readiness.png create mode 100644 static/assets/images/services/devsecops-consulting-advisory.png create mode 100644 static/assets/images/services/devsecops-consulting.png create mode 100644 static/assets/images/services/devsecops-enablement-training.png create mode 100644 static/assets/images/services/devsecops-security-tool-deployment.png create mode 100644 static/assets/images/services/digital-manufacturing.png create mode 100644 static/assets/images/services/digital-payments.png create mode 100644 static/assets/images/services/enterprise-support-services.png create mode 100644 static/assets/images/services/enterprise-support-training.png create mode 100644 static/assets/images/services/extending-kubernetes-comprehensive-guide-whitepaper.png create mode 100644 static/assets/images/services/fintech-financial-isvs.png create mode 100644 static/assets/images/services/gitops-consulting-implementation-hero.png create mode 100644 static/assets/images/services/gitops-implementation-dev-to-production.png create mode 100644 static/assets/images/services/gitops-tools-training.png create mode 100644 static/assets/images/services/grafana-alerting.png create mode 100644 static/assets/images/services/grafana-consulting-illustration.png create mode 100644 static/assets/images/services/grafana-data-integration.png create mode 100644 static/assets/images/services/grafana-reporting.png create mode 100644 static/assets/images/services/grafana-strategy-implementation.png create mode 100644 static/assets/images/services/iac-management.png create mode 100644 static/assets/images/services/implement-production-grade-backstage.png create mode 100644 static/assets/images/services/integration-deployment.png create mode 100644 static/assets/images/services/integration-with-tools-and-workflows.png create mode 100644 static/assets/images/services/integrations-ecosystem-setup.png create mode 100644 static/assets/images/services/istio-consulting-advisory.png create mode 100644 static/assets/images/services/istio-consulting-hero.png create mode 100644 static/assets/images/services/istio-consulting-implementation.png create mode 100644 static/assets/images/services/istio-consulting-security.png create mode 100644 static/assets/images/services/jenkins-consulting-best-practices.png create mode 100644 static/assets/images/services/jenkins-consulting-delivery-time.png create mode 100644 static/assets/images/services/jenkins-consulting-dev-lifecycle.png create mode 100644 static/assets/images/services/jenkins-consulting-devops.png create mode 100644 static/assets/images/services/jenkins-consulting-enterprise-support.png create mode 100644 static/assets/images/services/jenkins-consulting-training-support.png create mode 100644 static/assets/images/services/kubernetes-advisory.png create mode 100644 static/assets/images/services/kubernetes-application-development.png create mode 100644 static/assets/images/services/kubernetes-backup-data-protection.png create mode 100644 static/assets/images/services/kubernetes-business-continuity.png create mode 100644 static/assets/images/services/kubernetes-consulting.png create mode 100644 static/assets/images/services/kubernetes-consultings.png create mode 100644 static/assets/images/services/kubernetes-deployment-partner.png create mode 100644 static/assets/images/services/kubernetes-devsecops-compliance.png create mode 100644 static/assets/images/services/kubernetes-disaster-recovery-2.png create mode 100644 static/assets/images/services/kubernetes-disaster-recovery.png create mode 100644 static/assets/images/services/kubernetes-enterprise-support-training.png create mode 100644 static/assets/images/services/kubernetes-migration.png create mode 100644 static/assets/images/services/kubernetes-multi-cloud.png create mode 100644 static/assets/images/services/managed-devops-services.png create mode 100644 static/assets/images/services/managed-devsecops-services.png create mode 100644 static/assets/images/services/managed-services-continuous-support.png create mode 100644 static/assets/images/services/microservices-consulting-strategy.png create mode 100644 static/assets/images/services/microservices-integration-api-management.png create mode 100644 static/assets/images/services/microservices-support-monitoring-optimization.png create mode 100644 static/assets/images/services/monolith-microservices-modernization-hero.png create mode 100644 static/assets/images/services/monolith-to-microservices-migration.png create mode 100644 static/assets/images/services/mvp-strategy-platform-roadmap-consulting.png create mode 100644 static/assets/images/services/network-assessment-optimization.png create mode 100644 static/assets/images/services/network-automation-policy-management.png create mode 100644 static/assets/images/services/observability-consulting-hero.png create mode 100644 static/assets/images/services/observability-distributed-tracing.png create mode 100644 static/assets/images/services/observability-infrastructure-monitoring.png create mode 100644 static/assets/images/services/observability-traffic-management.png create mode 100644 static/assets/images/services/observability-unified-logging.png create mode 100644 static/assets/images/services/on-prem-hardware-to-maas-guidance.png create mode 100644 static/assets/images/services/on-prem-kubernetes-provisioning.png create mode 100644 static/assets/images/services/open-source.png create mode 100644 static/assets/images/services/platform-design-development.png create mode 100644 static/assets/images/services/platform-engineering-ebook-inside.png create mode 100644 static/assets/images/services/platform-engineering-ebook.png create mode 100644 static/assets/images/services/platform-engineering-training-enablement.png create mode 100644 static/assets/images/services/platform-support-maintenance.png create mode 100644 static/assets/images/services/process-design-implementation.png create mode 100644 static/assets/images/services/product-engineering-cloud-native-product-development-hero.png create mode 100644 static/assets/images/services/product-market-fit-assessment.png create mode 100644 static/assets/images/services/progressive-delivery-consulting-advisory.png create mode 100644 static/assets/images/services/progressive-delivery-consulting-implementation.png create mode 100644 static/assets/images/services/progressive-delivery-consulting-support.png create mode 100644 static/assets/images/services/progressive-delivery-consulting-training.png create mode 100644 static/assets/images/services/progressive-delivery-consulting.png create mode 100644 static/assets/images/services/prometheus-commercial-support-training.png create mode 100644 static/assets/images/services/prometheus-consulting-implementation.png create mode 100644 static/assets/images/services/prometheus-data-modeling-querying.png create mode 100644 static/assets/images/services/prometheus-incident-management.png create mode 100644 static/assets/images/services/prometheus-monitoring-support.png create mode 100644 static/assets/images/services/prometheus-third-party-integration.png create mode 100644 static/assets/images/services/retail-corporate-banking.png create mode 100644 static/assets/images/services/scalability-planning.png create mode 100644 static/assets/images/services/scalable-growth.png create mode 100644 static/assets/images/services/security-and-compliance-integration.png create mode 100644 static/assets/images/services/security-compliance.png create mode 100644 static/assets/images/services/serverless-consulting-hero.png create mode 100644 static/assets/images/services/serverless-implementation-services.png create mode 100644 static/assets/images/services/serverless-operations.png create mode 100644 static/assets/images/services/serverless-strategy-advisory.png create mode 100644 static/assets/images/services/service-mesh-consulting-advisory.png create mode 100644 static/assets/images/services/service-mesh-consulting-deployment.png create mode 100644 static/assets/images/services/service-mesh-consulting-integration.png create mode 100644 static/assets/images/services/service-mesh-consulting-support.png create mode 100644 static/assets/images/services/service-mesh-consulting.png create mode 100644 static/assets/images/services/sre-consulting-disaster-recovery.png create mode 100644 static/assets/images/services/sre-consulting-incident-management.png create mode 100644 static/assets/images/services/sre-consulting-infrastructure-management.png create mode 100644 static/assets/images/services/sre-consulting-observability.png create mode 100644 static/assets/images/services/sre-consulting-security-governance.png create mode 100644 static/assets/images/services/sre-consulting-services.png create mode 100644 static/assets/images/services/sre-consulting-strategy.png create mode 100644 static/assets/images/services/sre-consulting-training.png create mode 100644 static/assets/images/services/steps/build-mvp.png create mode 100644 static/assets/images/services/steps/development.png create mode 100644 static/assets/images/services/steps/discover-opportunities.png create mode 100644 static/assets/images/services/steps/launch.png create mode 100644 static/assets/images/services/steps/scale.png create mode 100644 static/assets/images/services/strategic-consulting-architecture-design.png create mode 100644 static/assets/images/services/terraform-cloud-enterprise.png create mode 100644 static/assets/images/services/terraform-consulting.png create mode 100644 static/assets/images/services/terragrunt.png create mode 100644 static/assets/images/services/tinkerbell-enterprise-support.png create mode 100644 static/assets/images/services/toolchain-analysis.png create mode 100644 static/assets/images/services/toolchain-training.png create mode 100644 static/assets/images/services/training-enablement.png create mode 100644 static/assets/images/services/upskilling-team-enablement.png create mode 100644 static/assets/images/services/why-should-read-paper.png create mode 100644 static/assets/images/technical-expertise/argocd.svg create mode 100644 static/assets/images/technical-expertise/crossplane.svg create mode 100644 static/assets/images/technical-expertise/fluxcd.svg create mode 100644 static/assets/images/technical-expertise/grafana.svg create mode 100644 static/assets/images/technical-expertise/graphql.svg create mode 100644 static/assets/images/technical-expertise/helm.svg create mode 100644 static/assets/images/technical-expertise/kasten.svg create mode 100644 static/assets/images/technical-expertise/kubernetes.svg create mode 100644 static/assets/images/technical-expertise/kustomize.png create mode 100644 static/assets/images/technical-expertise/open-policy-agent.png create mode 100644 static/assets/images/technical-expertise/prometheus.svg create mode 100644 static/assets/images/technical-expertise/terraform.svg create mode 100644 static/assets/images/technical-expertise/terragrunt.png create mode 100644 static/assets/images/technical-expertise/thanos.svg create mode 100644 static/assets/images/technical-expertise/werf.svg create mode 100644 static/files/products/appscode/aws-selfhost/iam-credential-manager-permissions.json create mode 100644 static/files/products/appscode/aws-selfhost/iam-ec2-permissions.json create mode 100644 static/files/products/appscode/aws-selfhost/iam-eks-permissions.json create mode 100644 static/files/products/appscode/aws-selfhost/iam-stash-permissions.json create mode 100644 static/files/products/appscode/aws-selfhost/template-trust-relationship diff --git a/content/docs/v2025.11.21/CHANGELOG-v2021.08.02.md b/content/docs/v2025.11.21/CHANGELOG-v2021.08.02.md new file mode 100644 index 000000000..ffeba9ef8 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2021.08.02.md @@ -0,0 +1,828 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2021.08.02 + name: Changelog-v2021.08.02 + parent: welcome + weight: 20210802 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2021.08.02/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2021.08.02/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2021.08.02 (2021-07-31) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.4.0](https://github.com/kubevault/apimachinery/releases/tag/v0.4.0) + +- [5bfb270b](https://github.com/kubevault/apimachinery/commit/5bfb270b) Update repository config (#19) +- [9945ca1b](https://github.com/kubevault/apimachinery/commit/9945ca1b) Update dependencies (#18) +- [777c84ac](https://github.com/kubevault/apimachinery/commit/777c84ac) Update constants with client certs volume name (#17) +- [ac376197](https://github.com/kubevault/apimachinery/commit/ac376197) Update volume name constants (#16) +- [c2d058b5](https://github.com/kubevault/apimachinery/commit/c2d058b5) Add constants for webhook api groups (#15) +- [79228320](https://github.com/kubevault/apimachinery/commit/79228320) Update README.md +- [c2cfc637](https://github.com/kubevault/apimachinery/commit/c2cfc637) Update README.md +- [1c799056](https://github.com/kubevault/apimachinery/commit/1c799056) Only generate crd v1 yamls (#14) +- [910a00b6](https://github.com/kubevault/apimachinery/commit/910a00b6) Add helper method for service template (#13) +- [81f6642e](https://github.com/kubevault/apimachinery/commit/81f6642e) Add StatefulSet watcher (#12) +- [880a2f1f](https://github.com/kubevault/apimachinery/commit/880a2f1f) Raft Vault Backend (#8) +- [c6233d6b](https://github.com/kubevault/apimachinery/commit/c6233d6b) Update audit event publisher (#10) +- [5ad33f62](https://github.com/kubevault/apimachinery/commit/5ad33f62) Update dependencies (#9) +- [c7d4a289](https://github.com/kubevault/apimachinery/commit/c7d4a289) Replace go-bindata with //go:embed (#7) +- [ee001880](https://github.com/kubevault/apimachinery/commit/ee001880) Add support for ES secret engine (#5) +- [a0cc7d66](https://github.com/kubevault/apimachinery/commit/a0cc7d66) Update log dependency +- [af048ed4](https://github.com/kubevault/apimachinery/commit/af048ed4) Cleanup log dependencies +- [7e862b1e](https://github.com/kubevault/apimachinery/commit/7e862b1e) Use k8s 1.21.0 toolchain (#6) +- [5a0081e2](https://github.com/kubevault/apimachinery/commit/5a0081e2) Revise VaultServer API +- [09f53328](https://github.com/kubevault/apimachinery/commit/09f53328) Update crds via GitHub actions (#3) +- [5738aa12](https://github.com/kubevault/apimachinery/commit/5738aa12) Update module path (#1) +- [35b08605](https://github.com/kubevault/apimachinery/commit/35b08605) Add Raft Backend (#334) +- [fc3c2168](https://github.com/kubevault/apimachinery/commit/fc3c2168) Use recommended Kubernetes app labels for offshoots (#336) +- [6d8cc33f](https://github.com/kubevault/apimachinery/commit/6d8cc33f) feat: Key-Value Secret Engine Configuration (#306) +- [93e3ddde](https://github.com/kubevault/apimachinery/commit/93e3ddde) fix: unify some tabs/spaces (#333) +- [6731ec82](https://github.com/kubevault/apimachinery/commit/6731ec82) feat: bump vault/sdk (#332) +- [549e710b](https://github.com/kubevault/apimachinery/commit/549e710b) Add auth ldap users/groups/oidc support (#269) +- [217e2542](https://github.com/kubevault/apimachinery/commit/217e2542) AppRole support (#266) +- [31984d48](https://github.com/kubevault/apimachinery/commit/31984d48) Update Kubernetes v1.18.9 dependencies (#328) +- [354a8b9a](https://github.com/kubevault/apimachinery/commit/354a8b9a) Update repository config (#330) +- [2b3ecef8](https://github.com/kubevault/apimachinery/commit/2b3ecef8) Update repository config (#329) +- [2887094a](https://github.com/kubevault/apimachinery/commit/2887094a) Update Kubernetes v1.18.9 dependencies (#327) +- [c6241f89](https://github.com/kubevault/apimachinery/commit/c6241f89) Update repository config (#326) +- [193c9ab3](https://github.com/kubevault/apimachinery/commit/193c9ab3) Update Kubernetes v1.18.9 dependencies (#325) +- [5e0397ac](https://github.com/kubevault/apimachinery/commit/5e0397ac) Update Kubernetes v1.18.9 dependencies (#324) +- [1d8dc478](https://github.com/kubevault/apimachinery/commit/1d8dc478) Update repository config (#323) +- [137ad084](https://github.com/kubevault/apimachinery/commit/137ad084) Update Kubernetes v1.18.9 dependencies (#322) +- [7c8956d9](https://github.com/kubevault/apimachinery/commit/7c8956d9) Update Kubernetes v1.18.9 dependencies (#320) +- [dd8bb6e5](https://github.com/kubevault/apimachinery/commit/dd8bb6e5) Update Kubernetes v1.18.9 dependencies (#319) +- [a9918d81](https://github.com/kubevault/apimachinery/commit/a9918d81) Update Kubernetes v1.18.9 dependencies (#318) +- [f1ec1261](https://github.com/kubevault/apimachinery/commit/f1ec1261) Update Kubernetes v1.18.9 dependencies (#316) +- [145d00da](https://github.com/kubevault/apimachinery/commit/145d00da) Update Kubernetes v1.18.9 dependencies (#315) +- [843635d5](https://github.com/kubevault/apimachinery/commit/843635d5) Update Kubernetes v1.18.9 dependencies (#314) +- [f5331347](https://github.com/kubevault/apimachinery/commit/f5331347) Update Kubernetes v1.18.9 dependencies (#313) +- [b502cc69](https://github.com/kubevault/apimachinery/commit/b502cc69) Update repository config (#312) +- [356167c7](https://github.com/kubevault/apimachinery/commit/356167c7) Update repository config (#311) +- [bd713135](https://github.com/kubevault/apimachinery/commit/bd713135) Update Kubernetes v1.18.9 dependencies (#309) +- [1dd9ef58](https://github.com/kubevault/apimachinery/commit/1dd9ef58) Publish docker images to ghcr.io (#310) +- [34faf04f](https://github.com/kubevault/apimachinery/commit/34faf04f) Update Kubernetes v1.18.9 dependencies (#307) +- [fa7c4889](https://github.com/kubevault/apimachinery/commit/fa7c4889) feat: allow imagePullPolicy in server definition (#289) +- [b4fe8ab9](https://github.com/kubevault/apimachinery/commit/b4fe8ab9) fix: conform to Kubernetes TLS key naming convention (#278) +- [7251a54f](https://github.com/kubevault/apimachinery/commit/7251a54f) Update Kubernetes v1.18.9 dependencies (#305) +- [311663bd](https://github.com/kubevault/apimachinery/commit/311663bd) Update Kubernetes v1.18.9 dependencies (#304) +- [fbbfa73c](https://github.com/kubevault/apimachinery/commit/fbbfa73c) Update repository config (#303) +- [a7e58a40](https://github.com/kubevault/apimachinery/commit/a7e58a40) Update repository config (#302) +- [97898a69](https://github.com/kubevault/apimachinery/commit/97898a69) Update Kubernetes v1.18.9 dependencies (#301) +- [659fd5a1](https://github.com/kubevault/apimachinery/commit/659fd5a1) Update Kubernetes v1.18.3 dependencies (#300) +- [d17d0287](https://github.com/kubevault/apimachinery/commit/d17d0287) Update Kubernetes v1.18.3 dependencies (#299) +- [a4d4271b](https://github.com/kubevault/apimachinery/commit/a4d4271b) Update Kubernetes v1.18.3 dependencies (#298) +- [951c1404](https://github.com/kubevault/apimachinery/commit/951c1404) Update Kubernetes v1.18.3 dependencies (#297) +- [da9d42fc](https://github.com/kubevault/apimachinery/commit/da9d42fc) Update Kubernetes v1.18.3 dependencies (#296) +- [3cd1e5b4](https://github.com/kubevault/apimachinery/commit/3cd1e5b4) Update Kubernetes v1.18.3 dependencies (#295) +- [87f6bc00](https://github.com/kubevault/apimachinery/commit/87f6bc00) Update Kubernetes v1.18.3 dependencies (#293) +- [023a3037](https://github.com/kubevault/apimachinery/commit/023a3037) Update Kubernetes v1.18.3 dependencies (#291) +- [3faaf3c6](https://github.com/kubevault/apimachinery/commit/3faaf3c6) Update Kubernetes v1.18.3 dependencies (#288) +- [a9bc351f](https://github.com/kubevault/apimachinery/commit/a9bc351f) Allow configuring k8s version in e2e tests (#283) +- [04c4ffb9](https://github.com/kubevault/apimachinery/commit/04c4ffb9) Update to Kubernetes v1.18.3 (#281) +- [753a1232](https://github.com/kubevault/apimachinery/commit/753a1232) Trigger e2e tests on /ok-to-test command (#277) +- [cb9a464d](https://github.com/kubevault/apimachinery/commit/cb9a464d) Update to Kubernetes v1.18.3 (#276) +- [b9a522df](https://github.com/kubevault/apimachinery/commit/b9a522df) Update to Kubernetes v1.18.3 (#275) +- [f333f964](https://github.com/kubevault/apimachinery/commit/f333f964) Update cloud credentials for e2e tests (#265) +- [d54ac86b](https://github.com/kubevault/apimachinery/commit/d54ac86b) Update to Kubernetes v1.18.3 (#273) +- [cec835f3](https://github.com/kubevault/apimachinery/commit/cec835f3) Update ci.yml +- [17fa4d10](https://github.com/kubevault/apimachinery/commit/17fa4d10) Update workflow name +- [692bf9da](https://github.com/kubevault/apimachinery/commit/692bf9da) Add workflow to update docs (#271) +- [fb728188](https://github.com/kubevault/apimachinery/commit/fb728188) Update update-release-tracker.sh +- [b8666d74](https://github.com/kubevault/apimachinery/commit/b8666d74) Update update-release-tracker.sh +- [bc8db8e2](https://github.com/kubevault/apimachinery/commit/bc8db8e2) Add script to update release tracker on pr merge (#270) +- [770eea2e](https://github.com/kubevault/apimachinery/commit/770eea2e) Update .kodiak.toml +- [aa795b6f](https://github.com/kubevault/apimachinery/commit/aa795b6f) Update to Kubernetes v1.18.3 (#268) +- [94711d90](https://github.com/kubevault/apimachinery/commit/94711d90) Update to Kubernetes v1.18.3 +- [e7b7bd8d](https://github.com/kubevault/apimachinery/commit/e7b7bd8d) Create .kodiak.toml +- [abe7175e](https://github.com/kubevault/apimachinery/commit/abe7175e) Merge pull request #263 from kubevault/x7 +- [55586dac](https://github.com/kubevault/apimachinery/commit/55586dac) Generate both v1beta1 and v1 CRD YAML +- [4c78651f](https://github.com/kubevault/apimachinery/commit/4c78651f) Merge status conditions +- [0a19f991](https://github.com/kubevault/apimachinery/commit/0a19f991) Update to Kubernetes v1.18.3 +- [e1885647](https://github.com/kubevault/apimachinery/commit/e1885647) Use standard conditions from kmodules (#261) +- [40d0d3b3](https://github.com/kubevault/apimachinery/commit/40d0d3b3) Fix Update***Status() helper methods (#260) +- [3ec9291d](https://github.com/kubevault/apimachinery/commit/3ec9291d) Update crazy-max/ghaction-docker-buildx flag +- [3bcbd919](https://github.com/kubevault/apimachinery/commit/3bcbd919) Use recommended kubernetes app labels (#259) +- [6eae4b23](https://github.com/kubevault/apimachinery/commit/6eae4b23) Add Enum markers to api types +- [32258c0a](https://github.com/kubevault/apimachinery/commit/32258c0a) Trigger the workflow on push or pull request +- [5d8af5e6](https://github.com/kubevault/apimachinery/commit/5d8af5e6) Use updated operator labels in e2e tests +- [1bf7785a](https://github.com/kubevault/apimachinery/commit/1bf7785a) Use kubectl 1.17 in CI (#256) +- [db50345d](https://github.com/kubevault/apimachinery/commit/db50345d) Pass image pull secrets to helm chart +- [13a38076](https://github.com/kubevault/apimachinery/commit/13a38076) Add license scan report and status (#255) +- [76851156](https://github.com/kubevault/apimachinery/commit/76851156) Update README.md +- [1c863530](https://github.com/kubevault/apimachinery/commit/1c863530) Prepare v0.3.0 release +- [f0d78928](https://github.com/kubevault/apimachinery/commit/f0d78928) Prepare v0.3.0-rc.0 release (#254) +- [8b5edb4c](https://github.com/kubevault/apimachinery/commit/8b5edb4c) Use Go 1.13.6 +- [158d84a8](https://github.com/kubevault/apimachinery/commit/158d84a8) Cleanup gendocs command (#253) +- [b6001ad6](https://github.com/kubevault/apimachinery/commit/b6001ad6) Enable tests for K8s 1.11 (#252) +- [8953ad57](https://github.com/kubevault/apimachinery/commit/8953ad57) Make volumeClaimTemplate field required (#250) +- [659420c7](https://github.com/kubevault/apimachinery/commit/659420c7) Add volumeClaimTemplates to the filesystem backend (#248) +- [073d2a43](https://github.com/kubevault/apimachinery/commit/073d2a43) Bring back support for k8s 1.11 (#249) +- [9a4d315f](https://github.com/kubevault/apimachinery/commit/9a4d315f) Pass public auth config via AppBinding spec.parameters (#246) +- [45495b1c](https://github.com/kubevault/apimachinery/commit/45495b1c) Update monitoring api (#247) +- [bd9215e0](https://github.com/kubevault/apimachinery/commit/bd9215e0) Update vaultpolicybinding_types.go +- [1647b4e6](https://github.com/kubevault/apimachinery/commit/1647b4e6) Use kind v0.6.1 +- [ba231cd6](https://github.com/kubevault/apimachinery/commit/ba231cd6) Stop uninstalling operation after e2e tests (#244) +- [f90a6b8f](https://github.com/kubevault/apimachinery/commit/f90a6b8f) Change crd label to app=kubevault (#243) +- [7e7d7c63](https://github.com/kubevault/apimachinery/commit/7e7d7c63) Delete installers and use Helm to install operator (#242) +- [fe6e6042](https://github.com/kubevault/apimachinery/commit/fe6e6042) Mark optional fields in Installer crd (#241) +- [37256833](https://github.com/kubevault/apimachinery/commit/37256833) charts/vault-operator: Allow specifying rather than generating c… (#238) +- [f4b2b9f4](https://github.com/kubevault/apimachinery/commit/f4b2b9f4) Add additional printerColumn to role crds (#240) +- [d70e550b](https://github.com/kubevault/apimachinery/commit/d70e550b) Use OwnerReference helpers from kmodules (#239) +- [bf4a6165](https://github.com/kubevault/apimachinery/commit/bf4a6165) Add installer api CRD (#237) +- [44746c7b](https://github.com/kubevault/apimachinery/commit/44746c7b) API review (#236) +- [4bb0b5cb](https://github.com/kubevault/apimachinery/commit/4bb0b5cb) Update dependencies +- [49c0bcf0](https://github.com/kubevault/apimachinery/commit/49c0bcf0) Run fuzz tests for generated API schemas (#235) +- [415f44c0](https://github.com/kubevault/apimachinery/commit/415f44c0) Don't preserveUnknownFields (#234) +- [7f046a7a](https://github.com/kubevault/apimachinery/commit/7f046a7a) Update client-go to kubernetes-1.16.3 (#231) +- [d1718ca3](https://github.com/kubevault/apimachinery/commit/d1718ca3) Set namespace for cleaner job (#233) +- [56d7b986](https://github.com/kubevault/apimachinery/commit/56d7b986) Properly handle empty image pull secret name in installer (#232) +- [fb44d8a3](https://github.com/kubevault/apimachinery/commit/fb44d8a3) Add helper library for CRDs (#230) +- [bc6db2ea](https://github.com/kubevault/apimachinery/commit/bc6db2ea) Use kubebuilder generated CRD yamls (#229) +- [6cc02611](https://github.com/kubevault/apimachinery/commit/6cc02611) Use controller-tools@v0.2.2 to generate structural schema (#228) +- [40568952](https://github.com/kubevault/apimachinery/commit/40568952) Generate protobuf files for api types (#227) +- [74aa1714](https://github.com/kubevault/apimachinery/commit/74aa1714) Add newline after copyright header +- [819025e0](https://github.com/kubevault/apimachinery/commit/819025e0) Test against multiple k8s versions (#224) +- [4973481c](https://github.com/kubevault/apimachinery/commit/4973481c) Test installers (#223) +- [7302432a](https://github.com/kubevault/apimachinery/commit/7302432a) Rename docker files +- [fe4bb858](https://github.com/kubevault/apimachinery/commit/fe4bb858) Update Makefile +- [bb2867cb](https://github.com/kubevault/apimachinery/commit/bb2867cb) Add license header to files (#222) +- [976db2a9](https://github.com/kubevault/apimachinery/commit/976db2a9) Use vault-unsealer@v0.3.0 (#221) +- [42b1b8ef](https://github.com/kubevault/apimachinery/commit/42b1b8ef) Split imports into 3 blocks (#220) +- [90da68cc](https://github.com/kubevault/apimachinery/commit/90da68cc) Enable make ci (#219) +- [0571dede](https://github.com/kubevault/apimachinery/commit/0571dede) Fix vault policy and policy binding (#217) +- [34b60582](https://github.com/kubevault/apimachinery/commit/34b60582) Change status.observedGeneration to int64 (#218) +- [34faa08b](https://github.com/kubevault/apimachinery/commit/34faa08b) Update ci.yml +- [ff56571d](https://github.com/kubevault/apimachinery/commit/ff56571d) Verify generated files are up to date (#216) +- [184bdc8c](https://github.com/kubevault/apimachinery/commit/184bdc8c) Use constants from kmodules.xyz/constants (#214) +- [b219dd43](https://github.com/kubevault/apimachinery/commit/b219dd43) Update workflow trigger events (#213) +- [036d2fbd](https://github.com/kubevault/apimachinery/commit/036d2fbd) Update Makefile +- [874b0f99](https://github.com/kubevault/apimachinery/commit/874b0f99) Generate swagger.json (#212) +- [4f0072f7](https://github.com/kubevault/apimachinery/commit/4f0072f7) Update release.yml +- [504b7b7e](https://github.com/kubevault/apimachinery/commit/504b7b7e) Add release workflow (#211) +- [d789a8ab](https://github.com/kubevault/apimachinery/commit/d789a8ab) Update Makefile +- [2cec9fca](https://github.com/kubevault/apimachinery/commit/2cec9fca) Use helper methods for loading cloud credentials (#210) +- [a4f0189b](https://github.com/kubevault/apimachinery/commit/a4f0189b) Run e2e tests using GitHub actions (#209) +- [4fcb2239](https://github.com/kubevault/apimachinery/commit/4fcb2239) Update go.yml +- [0cc4c6f8](https://github.com/kubevault/apimachinery/commit/0cc4c6f8) Download onessl version v0.13.1 for Kubernetes 1.16 fix (#208) +- [160ba2d8](https://github.com/kubevault/apimachinery/commit/160ba2d8) Enable GitHub actions +- [c8ace563](https://github.com/kubevault/apimachinery/commit/c8ace563) Link to the correct developer guide in docs repo (#205) +- [48076ab2](https://github.com/kubevault/apimachinery/commit/48076ab2) Major API Revision (#204) +- [d20edbb2](https://github.com/kubevault/apimachinery/commit/d20edbb2) Add SSmKeyPrefix option (#203) +- [c6ca898f](https://github.com/kubevault/apimachinery/commit/c6ca898f) Fix comments +- [15fce08f](https://github.com/kubevault/apimachinery/commit/15fce08f) Apply label to CRD yamls +- [4ba4d39e](https://github.com/kubevault/apimachinery/commit/4ba4d39e) Add naming patterns for CRDs +- [328a9529](https://github.com/kubevault/apimachinery/commit/328a9529) Use api folder like using kubebuilder +- [7bd9da99](https://github.com/kubevault/apimachinery/commit/7bd9da99) Use kubebuilder to generate crd yamls (#201) +- [1b010063](https://github.com/kubevault/apimachinery/commit/1b010063) Rename authManagerRef -> ref (#200) +- [bd5d1b95](https://github.com/kubevault/apimachinery/commit/bd5d1b95) Make api fields consistent (#199) +- [671c76ca](https://github.com/kubevault/apimachinery/commit/671c76ca) Update kubedb.dev/apimachinery paths (#198) +- [9fc37cd0](https://github.com/kubevault/apimachinery/commit/9fc37cd0) Update .travis.yml (#197) +- [f180c3db](https://github.com/kubevault/apimachinery/commit/f180c3db) Change package path to kubevault.dev/operator (#195) +- [1f4ef4dd](https://github.com/kubevault/apimachinery/commit/1f4ef4dd) Add license header to Makefiles (#194) +- [efe4cff6](https://github.com/kubevault/apimachinery/commit/efe4cff6) Set default securityContext.fsGroup to 65535 (#193) +- [36f4658b](https://github.com/kubevault/apimachinery/commit/36f4658b) Add make install, uninstall, purge commands (#192) +- [964bd5d3](https://github.com/kubevault/apimachinery/commit/964bd5d3) Allow mounting VolumeSource into vault container (#191) +- [f238768c](https://github.com/kubevault/apimachinery/commit/f238768c) Add Makefile (#190) +- [2192623d](https://github.com/kubevault/apimachinery/commit/2192623d) Add azure secret engine (#186) +- [a3ea6d6e](https://github.com/kubevault/apimachinery/commit/a3ea6d6e) Add azure role crd and crd controller (#185) +- [d698287d](https://github.com/kubevault/apimachinery/commit/d698287d) Add azure auth method (#181) +- [03543ee9](https://github.com/kubevault/apimachinery/commit/03543ee9) Use github.com/kubedb/apimachinery@0.12.0 +- [6fcb8816](https://github.com/kubevault/apimachinery/commit/6fcb8816) Update to k8s 1.14.0 client libraries using go.mod (#184) +- [d1ab12e8](https://github.com/kubevault/apimachinery/commit/d1ab12e8) Change different name for validators & mutators from CRD (#182) +- [363b9bf4](https://github.com/kubevault/apimachinery/commit/363b9bf4) Add GCP secret engine +- [deb98060](https://github.com/kubevault/apimachinery/commit/deb98060) Add GCPRole CRD Controller +- [a0827c22](https://github.com/kubevault/apimachinery/commit/a0827c22) Add Consul Backend Support +- [620915e8](https://github.com/kubevault/apimachinery/commit/620915e8) Add gcp auth support +- [65ae7670](https://github.com/kubevault/apimachinery/commit/65ae7670) Update kubedb client (#180) +- [f1e53b38](https://github.com/kubevault/apimachinery/commit/f1e53b38) Update Kubernetes client libraries to 1.13.5 +- [e870bd3b](https://github.com/kubevault/apimachinery/commit/e870bd3b) Update README.md +- [9997a562](https://github.com/kubevault/apimachinery/commit/9997a562) Update README.md +- [d69cb6f4](https://github.com/kubevault/apimachinery/commit/d69cb6f4) Prepare for 0.2.0 release (#174) +- [2ca2cdcc](https://github.com/kubevault/apimachinery/commit/2ca2cdcc) Update Kubernetes client libraries to 1.13.0 (#173) +- [3d3d33a6](https://github.com/kubevault/apimachinery/commit/3d3d33a6) Use kmodules packages directly. +- [98051f00](https://github.com/kubevault/apimachinery/commit/98051f00) Pass pod annotation to deployment (#172) +- [c574415f](https://github.com/kubevault/apimachinery/commit/c574415f) Don't use priority class when operator namespace is not kube-system (#171) +- [e525b8fa](https://github.com/kubevault/apimachinery/commit/e525b8fa) Use onessl 0.10.0 (#170) +- [572f25d2](https://github.com/kubevault/apimachinery/commit/572f25d2) Fix the case for deploying using MINGW64 for windows (#169) +- [e4e536e9](https://github.com/kubevault/apimachinery/commit/e4e536e9) Update KubeDB dependencies to 0.10.0 (#168) +- [1f115cef](https://github.com/kubevault/apimachinery/commit/1f115cef) Add mutating webhook for VaultServer (#166) +- [542e1345](https://github.com/kubevault/apimachinery/commit/542e1345) Update Catalog (#165) +- [ed2ac669](https://github.com/kubevault/apimachinery/commit/ed2ac669) Add cluster name flag in hack/deploy (#164) +- [9afcac92](https://github.com/kubevault/apimachinery/commit/9afcac92) Create stats service for vault server (#160) +- [824e623c](https://github.com/kubevault/apimachinery/commit/824e623c) Add appbinding user roles (#161) +- [98ca423d](https://github.com/kubevault/apimachinery/commit/98ca423d) Remove insecureSkipTLSVerify from Unsealer (#159) +- [d29c556f](https://github.com/kubevault/apimachinery/commit/d29c556f) Update copyright year (#158) +- [91a13cc2](https://github.com/kubevault/apimachinery/commit/91a13cc2) Apply various fixes to chart +- [a34761bb](https://github.com/kubevault/apimachinery/commit/a34761bb) Templatize service monitor name in chart +- [d5c458fb](https://github.com/kubevault/apimachinery/commit/d5c458fb) Add hooks for user roles to vault operator +- [fbda3acb](https://github.com/kubevault/apimachinery/commit/fbda3acb) Fix secret type in installer +- [5d6c9aa4](https://github.com/kubevault/apimachinery/commit/5d6c9aa4) Rename servicemonitor template installer +- [672dd867](https://github.com/kubevault/apimachinery/commit/672dd867) Fix service monitor template in chart +- [8046976f](https://github.com/kubevault/apimachinery/commit/8046976f) Use vault-operator.labels template in chart (#157) +- [12cc995a](https://github.com/kubevault/apimachinery/commit/12cc995a) Create apiserver cert before applying prometheus annotations in installer +- [bd30a17d](https://github.com/kubevault/apimachinery/commit/bd30a17d) Fix prometheus scrape annotations (#156) +- [6d8e444b](https://github.com/kubevault/apimachinery/commit/6d8e444b) Rename --monitor-operator variable in installer script (#155) +- [ea44041e](https://github.com/kubevault/apimachinery/commit/ea44041e) Various cleanup of installer script (#154) +- [4a5295fb](https://github.com/kubevault/apimachinery/commit/4a5295fb) Permit specifying compute resources for the operator container. (#153) +- [265d5cbb](https://github.com/kubevault/apimachinery/commit/265d5cbb) Use ca as CN for ca cert (#152) +- [ed16b1da](https://github.com/kubevault/apimachinery/commit/ed16b1da) Use cluster name flag to support multi-cluster setup (#149) +- [70794877](https://github.com/kubevault/apimachinery/commit/70794877) Add monitoring options to script installation (#147) +- [7cf0c2bd](https://github.com/kubevault/apimachinery/commit/7cf0c2bd) Add certificate health checker (#148) +- [254fa392](https://github.com/kubevault/apimachinery/commit/254fa392) Remove category all from VaultServerVersion crd (#146) +- [75fbec10](https://github.com/kubevault/apimachinery/commit/75fbec10) Add monitoring on helm installation (#145) +- [8420cc5b](https://github.com/kubevault/apimachinery/commit/8420cc5b) Fix rbac (#143) +- [f7328ba1](https://github.com/kubevault/apimachinery/commit/f7328ba1) Handle credential and connection url via db appbinding (#142) +- [1f1fe5c6](https://github.com/kubevault/apimachinery/commit/1f1fe5c6) Add dependency to kubedb/apimachinery to glide.yaml (#141) +- [f313def7](https://github.com/kubevault/apimachinery/commit/f313def7) Update webhook error message format for Kubernetes 1.13+ (#140) +- [b620b2e7](https://github.com/kubevault/apimachinery/commit/b620b2e7) Generate reference in docs repository (#139) +- [1eedc579](https://github.com/kubevault/apimachinery/commit/1eedc579) Merge commit '0da60ddec6a0719bfbb8a2b08a2ecff85e97fefb' +- [621fa5fb](https://github.com/kubevault/apimachinery/commit/621fa5fb) Remove openshift libraries from glide.yaml (#137) +- [3ac9f8d2](https://github.com/kubevault/apimachinery/commit/3ac9f8d2) Add AWSAccessKeyRequest validator (#136) +- [c449a437](https://github.com/kubevault/apimachinery/commit/c449a437) Add validation webhook xray (#135) +- [e2c009d9](https://github.com/kubevault/apimachinery/commit/e2c009d9) Update README.md +- [2b42b979](https://github.com/kubevault/apimachinery/commit/2b42b979) Rename api group secretengine to engine (#134) +- [909607ff](https://github.com/kubevault/apimachinery/commit/909607ff) Use flags.DumpAll (#133) +- [9f1859f5](https://github.com/kubevault/apimachinery/commit/9f1859f5) Add AWSAccessKeyRequest controller (#132) +- [e91aa997](https://github.com/kubevault/apimachinery/commit/e91aa997) Add AWSRole controller (#131) +- [dc23979f](https://github.com/kubevault/apimachinery/commit/dc23979f) Moved docs to kubevault/docs repo (#130) +- [69ad2c94](https://github.com/kubevault/apimachinery/commit/69ad2c94) Set periodic analytics (#128) +- [cad54833](https://github.com/kubevault/apimachinery/commit/cad54833) Update hack/deploy and add test for HA vault cluster (#125) +- [2ffba1bf](https://github.com/kubevault/apimachinery/commit/2ffba1bf) Delete vaultserverversions.catalog.kubevault.com.yaml +- [02627468](https://github.com/kubevault/apimachinery/commit/02627468) Revendor dependencies (#124) +- [70d60d3b](https://github.com/kubevault/apimachinery/commit/70d60d3b) Merge DB manager (#123) +- [738abbc8](https://github.com/kubevault/apimachinery/commit/738abbc8) Update README.md +- [3236183c](https://github.com/kubevault/apimachinery/commit/3236183c) Use Kubevault exporter image (#122) +- [9914c3fd](https://github.com/kubevault/apimachinery/commit/9914c3fd) Add Prometheus monitoring support via statsd_exporter (#118) +- [3238a562](https://github.com/kubevault/apimachinery/commit/3238a562) Fix e2e and unit test (#120) +- [81729d38](https://github.com/kubevault/apimachinery/commit/81729d38) Add Auth method controller (#119) +- [04660532](https://github.com/kubevault/apimachinery/commit/04660532) Add support for auth methods enabled in different path (#117) +- [de2a6fac](https://github.com/kubevault/apimachinery/commit/de2a6fac) Update kubernetes client libraries to 1.12.0 (#116) +- [35bc8c8c](https://github.com/kubevault/apimachinery/commit/35bc8c8c) Add controller for VaultPolicyBinding (#115) +- [f6dac864](https://github.com/kubevault/apimachinery/commit/f6dac864) Fix comment in chart (#114) +- [b22e707d](https://github.com/kubevault/apimachinery/commit/b22e707d) Use LogLevel in chart (#113) +- [6acdb331](https://github.com/kubevault/apimachinery/commit/6acdb331) Add controller for VaultPolicy (#112) +- [405cf0d5](https://github.com/kubevault/apimachinery/commit/405cf0d5) Enable webhooks by default in chart (#111) +- [edcbf7ba](https://github.com/kubevault/apimachinery/commit/edcbf7ba) Fix purging of VaultVersions xref: https://github.com/kubedb/cli/pull/311 +- [06695980](https://github.com/kubevault/apimachinery/commit/06695980) Add rbac permissions for catalog.kubevault.com (#110) +- [696db781](https://github.com/kubevault/apimachinery/commit/696db781) Move ***Version crds to catalog.kubedb.com apigroup (#108) +- [96171829](https://github.com/kubevault/apimachinery/commit/96171829) Update installation instructions for GKE (#107) +- [403c419f](https://github.com/kubevault/apimachinery/commit/403c419f) Add docs - part 1 (#52) +- [6682b293](https://github.com/kubevault/apimachinery/commit/6682b293) Update chart (#106) +- [3c5354dd](https://github.com/kubevault/apimachinery/commit/3c5354dd) Add validation webhook (#105) +- [a1303a6a](https://github.com/kubevault/apimachinery/commit/a1303a6a) Update docker image name +- [400ea34d](https://github.com/kubevault/apimachinery/commit/400ea34d) Add vault server version crd (#104) +- [efd464e2](https://github.com/kubevault/apimachinery/commit/efd464e2) Add init container for vault configuration (#103) +- [e84e321b](https://github.com/kubevault/apimachinery/commit/e84e321b) Add ensure operation, cleaup unused code (#101) +- [9c751fda](https://github.com/kubevault/apimachinery/commit/9c751fda) Use kubernetes-1.11.3 (#102) +- [36f2fa8f](https://github.com/kubevault/apimachinery/commit/36f2fa8f) Add revendor() to make.py +- [66c87791](https://github.com/kubevault/apimachinery/commit/66c87791) Generate crd yamls with fixed IntHash schema (#100) +- [bf71b91a](https://github.com/kubevault/apimachinery/commit/bf71b91a) Use IntHash as status.observedGeneration (#99) +- [30fa01b4](https://github.com/kubevault/apimachinery/commit/30fa01b4) Various improvements (#89) +- [93cc5d79](https://github.com/kubevault/apimachinery/commit/93cc5d79) Add support for swift storage (#98) +- [5b547c6c](https://github.com/kubevault/apimachinery/commit/5b547c6c) fix github status (#97) +- [3a71a8db](https://github.com/kubevault/apimachinery/commit/3a71a8db) Update pipeline (#96) +- [7f883c9f](https://github.com/kubevault/apimachinery/commit/7f883c9f) Add concourse configs (#95) +- [494fdb7c](https://github.com/kubevault/apimachinery/commit/494fdb7c) Improve Helm chart options (#94) +- [355170f7](https://github.com/kubevault/apimachinery/commit/355170f7) Merge commit '6c666ad3915a8d74e77e3c37a0e884824be06413' +- [94ce5f21](https://github.com/kubevault/apimachinery/commit/94ce5f21) Merge commit 'dd395466e617771a7c63e28583df5188609ccf38' +- [231fa24a](https://github.com/kubevault/apimachinery/commit/231fa24a) Enable status sub resource for crd yamls (#92) +- [2f7c46b0](https://github.com/kubevault/apimachinery/commit/2f7c46b0) Retry UpdateStatus calls (#91) +- [57f92a3c](https://github.com/kubevault/apimachinery/commit/57f92a3c) Move crds to api folder (#90) +- [3bf99494](https://github.com/kubevault/apimachinery/commit/3bf99494) Update README.md +- [ec9f028b](https://github.com/kubevault/apimachinery/commit/ec9f028b) Correctly handle ignored openapi prefixes (#87) +- [7dfe0cf7](https://github.com/kubevault/apimachinery/commit/7dfe0cf7) Add option for user provided tls (#86) +- [7bc8bcb2](https://github.com/kubevault/apimachinery/commit/7bc8bcb2) Set generated binary name to vault-operator (#85) +- [6a6b435d](https://github.com/kubevault/apimachinery/commit/6a6b435d) Use version and additional columns for crds (#83) +- [112e477e](https://github.com/kubevault/apimachinery/commit/112e477e) Add support for dynamoDB (#82) +- [0efdfc78](https://github.com/kubevault/apimachinery/commit/0efdfc78) Enable status subresource for crds (#81) +- [a173c80c](https://github.com/kubevault/apimachinery/commit/a173c80c) Format shell script (#80) +- [4ae31315](https://github.com/kubevault/apimachinery/commit/4ae31315) Merge commit '15621162a444c42ef3ac412966b9c0dd71cba919' +- [e04ef052](https://github.com/kubevault/apimachinery/commit/e04ef052) Update client-go to v8.0.0 (#79) +- [d7ed647e](https://github.com/kubevault/apimachinery/commit/d7ed647e) Add filesystem storage, add test and add filesystem spec doc (#78) +- [96f99f01](https://github.com/kubevault/apimachinery/commit/96f99f01) Add mySQL storage, add test and add mySQL spec doc (#77) +- [cecbf6dc](https://github.com/kubevault/apimachinery/commit/cecbf6dc) Add support for postgresSQL (#76) +- [fedd1a30](https://github.com/kubevault/apimachinery/commit/fedd1a30) Support for azure storage backend and azure key vault unsealer (#71) +- [832b29f5](https://github.com/kubevault/apimachinery/commit/832b29f5) Add aws s3 storage spec, awsKmsSsm unsealer, test and doc (#70) +- [c00690b0](https://github.com/kubevault/apimachinery/commit/c00690b0) Update email in swagger.json +- [76717072](https://github.com/kubevault/apimachinery/commit/76717072) Fix installer (#69) +- [76679c4d](https://github.com/kubevault/apimachinery/commit/76679c4d) Rename org to kubevault from kube-vault (#68) +- [a4217bf7](https://github.com/kubevault/apimachinery/commit/a4217bf7) Apply validation rules to vault server names (#67) +- [d697272e](https://github.com/kubevault/apimachinery/commit/d697272e) Move openapi-spec to api package (#66) +- [e8f143f9](https://github.com/kubevault/apimachinery/commit/e8f143f9) Add gcs backend storage, google kms gcs unsealer, test and doc (#65) +- [390e7d3c](https://github.com/kubevault/apimachinery/commit/390e7d3c) Add unsealer Spec (#64) +- [a39064a0](https://github.com/kubevault/apimachinery/commit/a39064a0) Fix badges (#62) +- [95bdc758](https://github.com/kubevault/apimachinery/commit/95bdc758) Merge commit '0c5a3e4064e0af66b622d7db546cfb94882932e8' +- [601cc304](https://github.com/kubevault/apimachinery/commit/601cc304) Update package path to github.com/kube-vault/operator (#61) +- [98c1b00c](https://github.com/kubevault/apimachinery/commit/98c1b00c) Add vault controller (#53) +- [8bed1bbc](https://github.com/kubevault/apimachinery/commit/8bed1bbc) Don't panic if admission options is nil (#59) +- [36a590a4](https://github.com/kubevault/apimachinery/commit/36a590a4) Update rbac permissions (#56) +- [0634165d](https://github.com/kubevault/apimachinery/commit/0634165d) Add Update***Status helpers (#55) +- [8fc3ab23](https://github.com/kubevault/apimachinery/commit/8fc3ab23) Update client-go to v7.0.0 (#54) +- [339e45c8](https://github.com/kubevault/apimachinery/commit/339e45c8) Update workload library (#51) +- [a97f4f81](https://github.com/kubevault/apimachinery/commit/a97f4f81) Improve installer (#50) +- [8f82a2b7](https://github.com/kubevault/apimachinery/commit/8f82a2b7) Fix installer (#49) +- [8c02c897](https://github.com/kubevault/apimachinery/commit/8c02c897) Update workload client (#48) +- [cfdb7ee3](https://github.com/kubevault/apimachinery/commit/cfdb7ee3) Update workload client (#47) +- [fafef7c5](https://github.com/kubevault/apimachinery/commit/fafef7c5) Update workload client (#46) +- [32a9d870](https://github.com/kubevault/apimachinery/commit/32a9d870) Add vault api (#45) +- [a6bfb7ca](https://github.com/kubevault/apimachinery/commit/a6bfb7ca) Update workload api (#44) +- [e915fafe](https://github.com/kubevault/apimachinery/commit/e915fafe) Switch to mutating webhook (#43) +- [ee00b369](https://github.com/kubevault/apimachinery/commit/ee00b369) Update vault deployment (#42) +- [d0080c2f](https://github.com/kubevault/apimachinery/commit/d0080c2f) Rename Secret to VaultSecret (#41) +- [f6690733](https://github.com/kubevault/apimachinery/commit/f6690733) Add installer scripts (#40) +- [16bdc1a5](https://github.com/kubevault/apimachinery/commit/16bdc1a5) Compress vault operator binary (#39) +- [0798cbfc](https://github.com/kubevault/apimachinery/commit/0798cbfc) Rename --analytics flag (#38) +- [845e981b](https://github.com/kubevault/apimachinery/commit/845e981b) Update docker build script (#37) +- [cf8337d1](https://github.com/kubevault/apimachinery/commit/cf8337d1) Merge commit '37ffb4e1649bb8bcbef55ddb79c1f0faf1c5dc5c' +- [3598a5ec](https://github.com/kubevault/apimachinery/commit/3598a5ec) Update .gitignore (#36) +- [f843d168](https://github.com/kubevault/apimachinery/commit/f843d168) Rename api types (#35) +- [8e7bab88](https://github.com/kubevault/apimachinery/commit/8e7bab88) Clone apis (#34) +- [effa39fd](https://github.com/kubevault/apimachinery/commit/effa39fd) Update links (#33) +- [72b59fc3](https://github.com/kubevault/apimachinery/commit/72b59fc3) Update chart (#32) +- [ab2708d3](https://github.com/kubevault/apimachinery/commit/ab2708d3) Update package path (#31) +- [615c5609](https://github.com/kubevault/apimachinery/commit/615c5609) Add travis yaml (#29) +- [488f9c61](https://github.com/kubevault/apimachinery/commit/488f9c61) Use NewUpsertHandler +- [ba58c573](https://github.com/kubevault/apimachinery/commit/ba58c573) Use shared informer factory (#28) +- [58404f33](https://github.com/kubevault/apimachinery/commit/58404f33) Update release.sh +- [ced844ed](https://github.com/kubevault/apimachinery/commit/ced844ed) Set analytics id +- [30382e5c](https://github.com/kubevault/apimachinery/commit/30382e5c) Merge commit 'a4eda21f482d329b4dc6619a3aaa29c0db0d161a' +- [e6509d38](https://github.com/kubevault/apimachinery/commit/e6509d38) Update client-go to v6.0.0 (#27) +- [00a9697d](https://github.com/kubevault/apimachinery/commit/00a9697d) Add front matter for steward cli (#25) +- [fa1d9b80](https://github.com/kubevault/apimachinery/commit/fa1d9b80) Cleanup release.sh script +- [d2c03588](https://github.com/kubevault/apimachinery/commit/d2c03588) Merge commit '4d8375ee9a3d5a55348e628f4f1166e412e8c677' +- [9785efad](https://github.com/kubevault/apimachinery/commit/9785efad) Add chart (#21) +- [924a1f20](https://github.com/kubevault/apimachinery/commit/924a1f20) Revendor kutil +- [8d858cd0](https://github.com/kubevault/apimachinery/commit/8d858cd0) Use client-go 5.x (#23) +- [f6fd476a](https://github.com/kubevault/apimachinery/commit/f6fd476a) Update vault to 0.8.3 +- [9047e975](https://github.com/kubevault/apimachinery/commit/9047e975) Update README.md +- [ea0006a6](https://github.com/kubevault/apimachinery/commit/ea0006a6) Update README.md +- [e6bea69d](https://github.com/kubevault/apimachinery/commit/e6bea69d) Renew token periodically (#19) +- [897c55e8](https://github.com/kubevault/apimachinery/commit/897c55e8) Add initializer for Controllers (#14) +- [26e64e14](https://github.com/kubevault/apimachinery/commit/26e64e14) Revise initializers (#12) +- [37e82399](https://github.com/kubevault/apimachinery/commit/37e82399) Fix initializers (#10) +- [46c98ce3](https://github.com/kubevault/apimachinery/commit/46c98ce3) Implement pod initializer and finalizer (#9) +- [f9e0fcf6](https://github.com/kubevault/apimachinery/commit/f9e0fcf6) Create vault secret for service account. (#8) +- [7135e3b2](https://github.com/kubevault/apimachinery/commit/7135e3b2) Initial skeleton (#1) +- [4d019d09](https://github.com/kubevault/apimachinery/commit/4d019d09) Merge commit '2b55cbba083cd47abad70528485c7c5319d071c9' as 'hack/libbuild' + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.4.0](https://github.com/kubevault/cli/releases/tag/v0.4.0) + +- [d6b8eed](https://github.com/kubevault/cli/commit/d6b8eed) Prepare for release v0.4.0 (#118) +- [b5dedb1](https://github.com/kubevault/cli/commit/b5dedb1) Update repository config (#117) +- [85dbd4f](https://github.com/kubevault/cli/commit/85dbd4f) Update repository config (#116) +- [7e65654](https://github.com/kubevault/cli/commit/7e65654) Update dependencies (#115) +- [b975866](https://github.com/kubevault/cli/commit/b975866) Fix build target +- [39dd95d](https://github.com/kubevault/cli/commit/39dd95d) Prepare for release v0.4.0-rc.0 (#114) +- [92ad95d](https://github.com/kubevault/cli/commit/92ad95d) Update README.md +- [8be750f](https://github.com/kubevault/cli/commit/8be750f) Update README.md +- [c1aab98](https://github.com/kubevault/cli/commit/c1aab98) Use kglog helpers +- [8a35eac](https://github.com/kubevault/cli/commit/8a35eac) Clean up depdenecies +- [f3c24c2](https://github.com/kubevault/cli/commit/f3c24c2) Use Kubernetes v1.21.0 toolchain (#113) +- [48d3ed9](https://github.com/kubevault/cli/commit/48d3ed9) Use Kubernetes v1.21.0 toolchain (#112) +- [76c709c](https://github.com/kubevault/cli/commit/76c709c) Use Kubernetes v1.21.0 toolchain (#111) +- [f23be1a](https://github.com/kubevault/cli/commit/f23be1a) Use Kubernetes v1.21.0 toolchain (#110) +- [f80b5dc](https://github.com/kubevault/cli/commit/f80b5dc) Use Kubernetes v1.21.0 toolchain (#109) +- [48dcb2b](https://github.com/kubevault/cli/commit/48dcb2b) Use Kubernetes v1.21.0 toolchain (#108) +- [062a763](https://github.com/kubevault/cli/commit/062a763) Update Kubernetes toolchain to v1.21.0 (#107) +- [a35db64](https://github.com/kubevault/cli/commit/a35db64) Update Kubernetes v1.18.9 dependencies (#106) +- [9a568de](https://github.com/kubevault/cli/commit/9a568de) Update Kubernetes v1.18.9 dependencies (#105) +- [9c5446a](https://github.com/kubevault/cli/commit/9c5446a) Update Kubernetes v1.18.9 dependencies (#104) +- [cfa9361](https://github.com/kubevault/cli/commit/cfa9361) Use kubevault.dev/apimachinery (#103) +- [9b2017f](https://github.com/kubevault/cli/commit/9b2017f) Use AppsCode Community License (#102) +- [03f21dd](https://github.com/kubevault/cli/commit/03f21dd) Update Kubernetes v1.18.9 dependencies (#101) +- [d339c04](https://github.com/kubevault/cli/commit/d339c04) Update Kubernetes v1.18.9 dependencies (#100) +- [716792b](https://github.com/kubevault/cli/commit/716792b) Update Kubernetes v1.18.9 dependencies (#99) +- [9bb9b59](https://github.com/kubevault/cli/commit/9bb9b59) Update Kubernetes v1.18.9 dependencies (#98) +- [af468d3](https://github.com/kubevault/cli/commit/af468d3) Update Kubernetes v1.18.9 dependencies (#97) +- [955654a](https://github.com/kubevault/cli/commit/955654a) Update Kubernetes v1.18.9 dependencies (#96) +- [8dd2afd](https://github.com/kubevault/cli/commit/8dd2afd) Update Kubernetes v1.18.9 dependencies (#95) +- [95b0884](https://github.com/kubevault/cli/commit/95b0884) Update Kubernetes v1.18.9 dependencies (#94) +- [610a54e](https://github.com/kubevault/cli/commit/610a54e) Update Kubernetes v1.18.9 dependencies (#93) +- [d24b2c9](https://github.com/kubevault/cli/commit/d24b2c9) Update Kubernetes v1.18.9 dependencies (#92) +- [fec50d3](https://github.com/kubevault/cli/commit/fec50d3) Update Kubernetes v1.18.9 dependencies (#91) +- [5e94b81](https://github.com/kubevault/cli/commit/5e94b81) Update Kubernetes v1.18.9 dependencies (#90) +- [fd95d33](https://github.com/kubevault/cli/commit/fd95d33) Update Kubernetes v1.18.9 dependencies (#89) +- [8628ae0](https://github.com/kubevault/cli/commit/8628ae0) Update Kubernetes v1.18.9 dependencies (#88) +- [c215e85](https://github.com/kubevault/cli/commit/c215e85) Update Kubernetes v1.18.9 dependencies (#87) +- [6bae8ca](https://github.com/kubevault/cli/commit/6bae8ca) Update Kubernetes v1.18.9 dependencies (#86) +- [a23403f](https://github.com/kubevault/cli/commit/a23403f) Update Kubernetes v1.18.9 dependencies (#85) +- [d7e5025](https://github.com/kubevault/cli/commit/d7e5025) Update Kubernetes v1.18.9 dependencies (#84) +- [3bf6d80](https://github.com/kubevault/cli/commit/3bf6d80) Update Kubernetes v1.18.9 dependencies (#83) +- [5484173](https://github.com/kubevault/cli/commit/5484173) Update Kubernetes v1.18.9 dependencies (#82) +- [f7476da](https://github.com/kubevault/cli/commit/f7476da) Update Kubernetes v1.18.9 dependencies (#81) +- [a1879e6](https://github.com/kubevault/cli/commit/a1879e6) Update Kubernetes v1.18.9 dependencies (#80) +- [9564d53](https://github.com/kubevault/cli/commit/9564d53) Update Kubernetes v1.18.9 dependencies (#79) +- [d911de7](https://github.com/kubevault/cli/commit/d911de7) Update Kubernetes v1.18.9 dependencies (#78) +- [b1207ec](https://github.com/kubevault/cli/commit/b1207ec) Update Kubernetes v1.18.9 dependencies (#77) +- [1b453f8](https://github.com/kubevault/cli/commit/1b453f8) Update Kubernetes v1.18.9 dependencies (#76) +- [7512363](https://github.com/kubevault/cli/commit/7512363) Update Kubernetes v1.18.9 dependencies (#75) +- [2d69fa4](https://github.com/kubevault/cli/commit/2d69fa4) Update Kubernetes v1.18.9 dependencies (#74) +- [ce26d68](https://github.com/kubevault/cli/commit/ce26d68) Update Kubernetes v1.18.9 dependencies (#73) +- [5f7e5db](https://github.com/kubevault/cli/commit/5f7e5db) Update Kubernetes v1.18.9 dependencies (#72) +- [561a39f](https://github.com/kubevault/cli/commit/561a39f) Update Kubernetes v1.18.9 dependencies (#71) +- [f470dd7](https://github.com/kubevault/cli/commit/f470dd7) Update Kubernetes v1.18.9 dependencies (#70) +- [77f4192](https://github.com/kubevault/cli/commit/77f4192) Update Kubernetes v1.18.9 dependencies (#69) +- [bd18155](https://github.com/kubevault/cli/commit/bd18155) Update Kubernetes v1.18.9 dependencies (#68) +- [dabf444](https://github.com/kubevault/cli/commit/dabf444) Update Kubernetes v1.18.9 dependencies (#67) +- [83a5f18](https://github.com/kubevault/cli/commit/83a5f18) Update Kubernetes v1.18.9 dependencies (#66) +- [5a3cbc4](https://github.com/kubevault/cli/commit/5a3cbc4) Update Kubernetes v1.18.9 dependencies (#65) +- [43e7e13](https://github.com/kubevault/cli/commit/43e7e13) Update Kubernetes v1.18.9 dependencies (#64) +- [870a9d4](https://github.com/kubevault/cli/commit/870a9d4) Update Kubernetes v1.18.9 dependencies (#63) +- [c4e9023](https://github.com/kubevault/cli/commit/c4e9023) Update Kubernetes v1.18.9 dependencies (#62) +- [1143d99](https://github.com/kubevault/cli/commit/1143d99) Update Kubernetes v1.18.9 dependencies (#61) +- [ebfe0aa](https://github.com/kubevault/cli/commit/ebfe0aa) Update Kubernetes v1.18.9 dependencies (#60) +- [958ffb5](https://github.com/kubevault/cli/commit/958ffb5) Update Kubernetes v1.18.9 dependencies (#59) +- [b687a25](https://github.com/kubevault/cli/commit/b687a25) Update Kubernetes v1.18.9 dependencies (#58) +- [1b1f9bc](https://github.com/kubevault/cli/commit/1b1f9bc) Update Kubernetes v1.18.9 dependencies (#57) +- [82f0bad](https://github.com/kubevault/cli/commit/82f0bad) Update Kubernetes v1.18.9 dependencies (#56) +- [7adf75a](https://github.com/kubevault/cli/commit/7adf75a) Update Kubernetes v1.18.9 dependencies (#55) +- [d686179](https://github.com/kubevault/cli/commit/d686179) Update Kubernetes v1.18.9 dependencies (#54) +- [23e85e1](https://github.com/kubevault/cli/commit/23e85e1) Update Kubernetes v1.18.9 dependencies (#53) +- [b2cb424](https://github.com/kubevault/cli/commit/b2cb424) Update Kubernetes v1.18.9 dependencies (#52) +- [8eb2556](https://github.com/kubevault/cli/commit/8eb2556) Update Kubernetes v1.18.9 dependencies (#51) +- [e69feec](https://github.com/kubevault/cli/commit/e69feec) Update Kubernetes v1.18.9 dependencies (#50) +- [350ec36](https://github.com/kubevault/cli/commit/350ec36) Update Kubernetes v1.18.9 dependencies (#49) +- [77b7367](https://github.com/kubevault/cli/commit/77b7367) Update Kubernetes v1.18.9 dependencies (#48) +- [b3175a7](https://github.com/kubevault/cli/commit/b3175a7) Update Kubernetes v1.18.9 dependencies (#47) +- [47bd336](https://github.com/kubevault/cli/commit/47bd336) Update Kubernetes v1.18.9 dependencies (#46) +- [3f720a8](https://github.com/kubevault/cli/commit/3f720a8) Update Kubernetes v1.18.9 dependencies (#45) +- [a67af01](https://github.com/kubevault/cli/commit/a67af01) Update Kubernetes v1.18.9 dependencies (#44) +- [0661132](https://github.com/kubevault/cli/commit/0661132) Update Kubernetes v1.18.9 dependencies (#43) +- [232dea1](https://github.com/kubevault/cli/commit/232dea1) Update Kubernetes v1.18.9 dependencies (#42) +- [2591d7d](https://github.com/kubevault/cli/commit/2591d7d) Update Kubernetes v1.18.9 dependencies (#41) +- [72f4933](https://github.com/kubevault/cli/commit/72f4933) Update Kubernetes v1.18.9 dependencies (#40) +- [b96918d](https://github.com/kubevault/cli/commit/b96918d) Update Kubernetes v1.18.9 dependencies (#39) +- [6ec8c36](https://github.com/kubevault/cli/commit/6ec8c36) Update Kubernetes v1.18.9 dependencies (#38) +- [29324c0](https://github.com/kubevault/cli/commit/29324c0) Update Kubernetes v1.18.9 dependencies (#37) +- [e1893db](https://github.com/kubevault/cli/commit/e1893db) Update Kubernetes v1.18.9 dependencies (#36) +- [40f6162](https://github.com/kubevault/cli/commit/40f6162) Update Kubernetes v1.18.9 dependencies (#35) +- [cca7ff7](https://github.com/kubevault/cli/commit/cca7ff7) Update Kubernetes v1.18.9 dependencies (#33) +- [e7b3f41](https://github.com/kubevault/cli/commit/e7b3f41) Fix release workflow for plugin +- [f29598c](https://github.com/kubevault/cli/commit/f29598c) Fix license file extension +- [65fa01a](https://github.com/kubevault/cli/commit/65fa01a) Publish to krew index (#34) +- [cd5a4dd](https://github.com/kubevault/cli/commit/cd5a4dd) Add completion command (#32) +- [1f43dc9](https://github.com/kubevault/cli/commit/1f43dc9) Use actions/upload-artifact@v2 +- [d672d6d](https://github.com/kubevault/cli/commit/d672d6d) Prepare for release v0.4.0-beta.0 (#31) +- [3795bce](https://github.com/kubevault/cli/commit/3795bce) Add request's phase from cli (#30) +- [1e2bd37](https://github.com/kubevault/cli/commit/1e2bd37) Update workflow step name +- [18ce00b](https://github.com/kubevault/cli/commit/18ce00b) Add workflow to update docs (#29) +- [2767953](https://github.com/kubevault/cli/commit/2767953) Update update-release-tracker.sh +- [8f3dbe9](https://github.com/kubevault/cli/commit/8f3dbe9) Update update-release-tracker.sh +- [3a946a6](https://github.com/kubevault/cli/commit/3a946a6) Add script to update release tracker on pr merge (#28) +- [0656f6d](https://github.com/kubevault/cli/commit/0656f6d) Make release non-draft +- [cde187c](https://github.com/kubevault/cli/commit/cde187c) Update .kodiak.toml +- [06626ea](https://github.com/kubevault/cli/commit/06626ea) Create .kodiak.toml +- [724552d](https://github.com/kubevault/cli/commit/724552d) Add blank line after license header (#27) +- [87f1090](https://github.com/kubevault/cli/commit/87f1090) Update dependencies (#26) +- [11f6a44](https://github.com/kubevault/cli/commit/11f6a44) Update to Kubernetes v1.18.3 (#25) +- [6024a30](https://github.com/kubevault/cli/commit/6024a30) Update api types (#24) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2021.08.02](https://github.com/kubevault/installer/releases/tag/v2021.08.02) + +- [7e69ed8](https://github.com/kubevault/installer/commit/7e69ed8) Prepare for release v2021.08.02 (#119) +- [8cadeb5](https://github.com/kubevault/installer/commit/8cadeb5) Update dependencies (#118) +- [ce56c90](https://github.com/kubevault/installer/commit/ce56c90) Update permission for deleting ClusterRoleBinding (#117) +- [6544c9f](https://github.com/kubevault/installer/commit/6544c9f) Remove csi-vault chart +- [eac9ec7](https://github.com/kubevault/installer/commit/eac9ec7) Remove csi-vault installer chart (#116) +- [caab141](https://github.com/kubevault/installer/commit/caab141) Update vault unsealer images (#114) +- [5657185](https://github.com/kubevault/installer/commit/5657185) Update chart docs +- [1bf5f20](https://github.com/kubevault/installer/commit/1bf5f20) Update kubevault chart dependencies via Makefile (#113) +- [a19a644](https://github.com/kubevault/installer/commit/a19a644) Use latest helm cli (#112) +- [54977c2](https://github.com/kubevault/installer/commit/54977c2) Prepare for release v2021.07.14-rc.0 (#111) +- [bb0767c](https://github.com/kubevault/installer/commit/bb0767c) Update kubevault operator tag +- [b93e426](https://github.com/kubevault/installer/commit/b93e426) Use helm v3.6.2 +- [1660cdd](https://github.com/kubevault/installer/commit/1660cdd) Fix installer chart (#110) +- [1850085](https://github.com/kubevault/installer/commit/1850085) Create combined kubevault chart (#109) +- [63f21b9](https://github.com/kubevault/installer/commit/63f21b9) Update README.md +- [cf38d33](https://github.com/kubevault/installer/commit/cf38d33) Stop using deprecated admissionregistration.k8s.io/v1beta1 api (#108) +- [da8e9a0](https://github.com/kubevault/installer/commit/da8e9a0) Only use crd v1 version (#107) +- [d8d9df6](https://github.com/kubevault/installer/commit/d8d9df6) Update crds (#105) +- [bd3512b](https://github.com/kubevault/installer/commit/bd3512b) Update CSI driver sidecar images (#104) +- [060c70d](https://github.com/kubevault/installer/commit/060c70d) Remove reference to DB +- [05e435c](https://github.com/kubevault/installer/commit/05e435c) Add support for Vault Server version upto 1.7.3 (#101) +- [4bfd90e](https://github.com/kubevault/installer/commit/4bfd90e) Sort crd YAMLs by GK +- [dd0bb3f](https://github.com/kubevault/installer/commit/dd0bb3f) Merge metrics chart into crds chart +- [0b6ba4b](https://github.com/kubevault/installer/commit/0b6ba4b) Require Kubernetes 1.16+ +- [aac5360](https://github.com/kubevault/installer/commit/aac5360) Add registryFQDN and kubevault namespace (#103) +- [04fa310](https://github.com/kubevault/installer/commit/04fa310) Rename user-roles.yaml to metrics-user-roles.yaml +- [bc8678e](https://github.com/kubevault/installer/commit/bc8678e) Add kubevault-metrics chart (#102) +- [776d9fe](https://github.com/kubevault/installer/commit/776d9fe) Update chart description +- [9e19129](https://github.com/kubevault/installer/commit/9e19129) Fix build (#100) +- [48cc7c9](https://github.com/kubevault/installer/commit/48cc7c9) Add license verifier (#99) +- [30442cb](https://github.com/kubevault/installer/commit/30442cb) Revert "Add permissions for flowcontrol API (#98)" +- [6be5c12](https://github.com/kubevault/installer/commit/6be5c12) Add permissions for flowcontrol API (#98) +- [911d375](https://github.com/kubevault/installer/commit/911d375) Update Kubernetes toolchain to v1.21.0 (#97) +- [87e3ec7](https://github.com/kubevault/installer/commit/87e3ec7) Generate crd YAML file +- [91d69c8](https://github.com/kubevault/installer/commit/91d69c8) Auto download api repo to update crds (#96) +- [f840087](https://github.com/kubevault/installer/commit/f840087) Add ct.sh script (#95) +- [5236ab1](https://github.com/kubevault/installer/commit/5236ab1) make ct (#93) +- [50eb642](https://github.com/kubevault/installer/commit/50eb642) Remove unused templates from chart +- [155025d](https://github.com/kubevault/installer/commit/155025d) Update repository config (#92) +- [e957191](https://github.com/kubevault/installer/commit/e957191) Update crds for kubevault/apimachinery@09f53328 (#91) +- [61d3086](https://github.com/kubevault/installer/commit/61d3086) Add open-pr.sh script (#90) +- [11c5c45](https://github.com/kubevault/installer/commit/11c5c45) Add kubevault-crds chart (#89) +- [cb16b7f](https://github.com/kubevault/installer/commit/cb16b7f) Rename kubevault chart to kubevault-community (#88) +- [d924ba6](https://github.com/kubevault/installer/commit/d924ba6) Skip generating YAMLs not needed for install command (#86) +- [d60efde](https://github.com/kubevault/installer/commit/d60efde) Update repository config (#85) +- [9f01ff5](https://github.com/kubevault/installer/commit/9f01ff5) Use AppsCode Community License (#83) +- [b910712](https://github.com/kubevault/installer/commit/b910712) Update repository config (#84) +- [be28b6b](https://github.com/kubevault/installer/commit/be28b6b) Use Statefulsets instead of deployments as Vault pods (#82) +- [9cd700b](https://github.com/kubevault/installer/commit/9cd700b) Fix vault-operator chart +- [ac8b3a4](https://github.com/kubevault/installer/commit/ac8b3a4) Speed up schema generation process (#81) +- [7995678](https://github.com/kubevault/installer/commit/7995678) Update repository config (#80) +- [243ecd3](https://github.com/kubevault/installer/commit/243ecd3) Update repository config (#79) +- [6f86355](https://github.com/kubevault/installer/commit/6f86355) Update Kubernetes v1.18.9 dependencies (#78) +- [92ab8b7](https://github.com/kubevault/installer/commit/92ab8b7) Use apiregistration.k8s.io/v1 (#77) +- [0467764](https://github.com/kubevault/installer/commit/0467764) Update repository config (#76) +- [4b71f9e](https://github.com/kubevault/installer/commit/4b71f9e) Update Kubernetes v1.18.9 dependencies (#75) +- [cf86b08](https://github.com/kubevault/installer/commit/cf86b08) Update Kubernetes v1.18.9 dependencies (#74) +- [cb0f47b](https://github.com/kubevault/installer/commit/cb0f47b) Update Kubernetes v1.18.9 dependencies (#73) +- [e177169](https://github.com/kubevault/installer/commit/e177169) Update Kubernetes v1.18.9 dependencies (#72) +- [f5adf3d](https://github.com/kubevault/installer/commit/f5adf3d) Update Kubernetes v1.18.9 dependencies (#70) +- [bc7cd99](https://github.com/kubevault/installer/commit/bc7cd99) Update repository config (#69) +- [91b238c](https://github.com/kubevault/installer/commit/91b238c) Update repository config (#68) +- [3e39e9f](https://github.com/kubevault/installer/commit/3e39e9f) Update Kubernetes v1.18.9 dependencies (#67) +- [44e18ae](https://github.com/kubevault/installer/commit/44e18ae) Update Kubernetes v1.18.9 dependencies (#66) +- [1e172ee](https://github.com/kubevault/installer/commit/1e172ee) Update repository config (#65) +- [42789bf](https://github.com/kubevault/installer/commit/42789bf) Update repository config (#64) +- [6eae6f1](https://github.com/kubevault/installer/commit/6eae6f1) Update Kubernetes v1.18.9 dependencies (#63) +- [2e0ac6a](https://github.com/kubevault/installer/commit/2e0ac6a) Update Kubernetes v1.18.3 dependencies (#62) +- [98ed7e5](https://github.com/kubevault/installer/commit/98ed7e5) Update Kubernetes v1.18.3 dependencies (#61) +- [65b5017](https://github.com/kubevault/installer/commit/65b5017) Update Kubernetes v1.18.3 dependencies (#60) +- [8e30a29](https://github.com/kubevault/installer/commit/8e30a29) Update Kubernetes v1.18.3 dependencies (#59) +- [0fcfda6](https://github.com/kubevault/installer/commit/0fcfda6) Update Kubernetes v1.18.3 dependencies (#58) +- [0d51ba6](https://github.com/kubevault/installer/commit/0d51ba6) Update Kubernetes v1.18.3 dependencies (#57) +- [a1195df](https://github.com/kubevault/installer/commit/a1195df) Update Kubernetes v1.18.3 dependencies (#55) +- [63fa4c1](https://github.com/kubevault/installer/commit/63fa4c1) Update Kubernetes v1.18.3 dependencies (#54) +- [fcc714f](https://github.com/kubevault/installer/commit/fcc714f) Update Kubernetes v1.18.3 dependencies (#53) +- [2399dd6](https://github.com/kubevault/installer/commit/2399dd6) Update Kubernetes v1.18.3 dependencies (#52) +- [da88d4d](https://github.com/kubevault/installer/commit/da88d4d) Update Kubernetes v1.18.3 dependencies (#51) +- [b860089](https://github.com/kubevault/installer/commit/b860089) Update Kubernetes v1.18.3 dependencies (#50) +- [ad6d2c2](https://github.com/kubevault/installer/commit/ad6d2c2) Update to Kubernetes v1.18.3 (#48) +- [8e514f8](https://github.com/kubevault/installer/commit/8e514f8) Update to Kubernetes v1.18.3 (#47) +- [7f8018f](https://github.com/kubevault/installer/commit/7f8018f) Update to Kubernetes v1.18.3 (#46) +- [7591486](https://github.com/kubevault/installer/commit/7591486) Make chart registry configurable +- [c2ecf31](https://github.com/kubevault/installer/commit/c2ecf31) Prepare for release v0.4.0-beta.0 (#45) +- [c797b2c](https://github.com/kubevault/installer/commit/c797b2c) Publish to testing dir for alpha/beta releases +- [b1a2107](https://github.com/kubevault/installer/commit/b1a2107) Add permission to delete services and secrets (#44) +- [025425b](https://github.com/kubevault/installer/commit/025425b) Update to Kubernetes v1.18.3 (#43) +- [0ca3cc1](https://github.com/kubevault/installer/commit/0ca3cc1) Update ci.yml +- [e611b96](https://github.com/kubevault/installer/commit/e611b96) Tag chart and app version as string for yq +- [71f5996](https://github.com/kubevault/installer/commit/71f5996) Update links (#42) +- [3e96573](https://github.com/kubevault/installer/commit/3e96573) Update update-release-tracker.sh +- [3f2e808](https://github.com/kubevault/installer/commit/3f2e808) Update update-release-tracker.sh +- [1f9f83f](https://github.com/kubevault/installer/commit/1f9f83f) Update release.yml +- [f8ae615](https://github.com/kubevault/installer/commit/f8ae615) Add script to update release tracker on pr merge (#41) +- [8c94858](https://github.com/kubevault/installer/commit/8c94858) Update ci.yml +- [8a90cf4](https://github.com/kubevault/installer/commit/8a90cf4) Update ci workflow +- [31f593d](https://github.com/kubevault/installer/commit/31f593d) Revise update-charts rule (#40) +- [acf626b](https://github.com/kubevault/installer/commit/acf626b) Add commands to update chart (#39) +- [aa62d4a](https://github.com/kubevault/installer/commit/aa62d4a) Fix chart release process (#38) +- [bcd1a52](https://github.com/kubevault/installer/commit/bcd1a52) Update .kodiak.toml +- [82e7751](https://github.com/kubevault/installer/commit/82e7751) Update to Kubernetes v1.18.3 (#33) +- [b5629e8](https://github.com/kubevault/installer/commit/b5629e8) Update to Kubernetes v1.18.3 +- [43b1ccd](https://github.com/kubevault/installer/commit/43b1ccd) Create .kodiak.toml +- [3ba9834](https://github.com/kubevault/installer/commit/3ba9834) Permit configmap list/watch for delegated authentication (#31) +- [8f5eb5e](https://github.com/kubevault/installer/commit/8f5eb5e) Update to Kubernetes v1.18.3 (#30) +- [12d45b4](https://github.com/kubevault/installer/commit/12d45b4) Update catalog template file name + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.4.0](https://github.com/kubevault/operator/releases/tag/v0.4.0) + +- [ad15b48a](https://github.com/kubevault/operator/commit/ad15b48a) Prepare for release v0.4.0 (#12) +- [0087d972](https://github.com/kubevault/operator/commit/0087d972) Update VaultServer mutator to set default values (#10) +- [fe5a3b7d](https://github.com/kubevault/operator/commit/fe5a3b7d) Update dependencies (#9) +- [f7fb9565](https://github.com/kubevault/operator/commit/f7fb9565) Fix stats-service, vaultpolicybinding patching & ClusterRoleBinding deletion issue (#8) +- [e1a6d3e5](https://github.com/kubevault/operator/commit/e1a6d3e5) Use client certs in exporter sidecar (#7) +- [9e4d02b5](https://github.com/kubevault/operator/commit/9e4d02b5) Use certificate file paths in exporter sidecar (#6) +- [368b84f5](https://github.com/kubevault/operator/commit/368b84f5) Make license optional for dev builds (#5) +- [ead1c672](https://github.com/kubevault/operator/commit/ead1c672) Return nil if cert secrets are created successfully (#4) +- [63285306](https://github.com/kubevault/operator/commit/63285306) Restrict to default namespace for community license (#3) +- [374554d4](https://github.com/kubevault/operator/commit/374554d4) Install Go in release workflow +- [f4f176f6](https://github.com/kubevault/operator/commit/f4f176f6) Stop using deprecated apis (#2) +- [c4c0f934](https://github.com/kubevault/operator/commit/c4c0f934) Fix make install command +- [c21f2ea9](https://github.com/kubevault/operator/commit/c21f2ea9) Prepare for release v0.4.0-rc.0 (#1) +- [80b30ab0](https://github.com/kubevault/operator/commit/80b30ab0) Update readme +- [60512f3c](https://github.com/kubevault/operator/commit/60512f3c) Fix repetitive patch of Statefulset (#356) +- [d9e50519](https://github.com/kubevault/operator/commit/d9e50519) Add VaultServer Phases (#355) +- [619d38bf](https://github.com/kubevault/operator/commit/619d38bf) Add support for terminationPolicy (#354) +- [5decf23f](https://github.com/kubevault/operator/commit/5decf23f) Add Support for Vault Raft Storage Backend (#349) +- [90686c44](https://github.com/kubevault/operator/commit/90686c44) Use kubevault namespace +- [2f1bce13](https://github.com/kubevault/operator/commit/2f1bce13) Update audit lib (#353) +- [05d34f43](https://github.com/kubevault/operator/commit/05d34f43) Send audit events when analytics are enabled (#352) +- [efc8dac7](https://github.com/kubevault/operator/commit/efc8dac7) Create auditor if license file is provided (#351) +- [0d895890](https://github.com/kubevault/operator/commit/0d895890) Publish audit events (#350) +- [470b3aa2](https://github.com/kubevault/operator/commit/470b3aa2) Add support for ES secret engine (#347) +- [8bd884b5](https://github.com/kubevault/operator/commit/8bd884b5) Update Kubernetes toolchain to v1.21.0 (#348) +- [2a7da741](https://github.com/kubevault/operator/commit/2a7da741) Revise vaultserver API +- [af4b66e8](https://github.com/kubevault/operator/commit/af4b66e8) Update repository config (#345) +- [53c96da8](https://github.com/kubevault/operator/commit/53c96da8) Update repository config (#344) +- [290cfb28](https://github.com/kubevault/operator/commit/290cfb28) Update Kubernetes v1.18.9 dependencies (#343) +- [3f84dcf8](https://github.com/kubevault/operator/commit/3f84dcf8) Update Kubernetes v1.18.9 dependencies (#342) +- [915b7af6](https://github.com/kubevault/operator/commit/915b7af6) Update repository config (#341) +- [b998b5be](https://github.com/kubevault/operator/commit/b998b5be) Update repository config (#340) +- [6f2b94aa](https://github.com/kubevault/operator/commit/6f2b94aa) Update Kubernetes v1.18.9 dependencies (#339) +- [ebb9afa3](https://github.com/kubevault/operator/commit/ebb9afa3) Use AppsCode Community License (#337) +- [0c80fdb4](https://github.com/kubevault/operator/commit/0c80fdb4) Add Raft Backend (#334) +- [d4f5575d](https://github.com/kubevault/operator/commit/d4f5575d) Use recommended Kubernetes app labels for offshoots (#336) +- [78556275](https://github.com/kubevault/operator/commit/78556275) Fix build (#335) +- [14db9b72](https://github.com/kubevault/operator/commit/14db9b72) feat: Key-Value Secret Engine Configuration (#306) +- [3bf9e1f4](https://github.com/kubevault/operator/commit/3bf9e1f4) fix: searching for token secret explicitly (#294) +- [c5293adf](https://github.com/kubevault/operator/commit/c5293adf) fix: ClusterRoleBinding has no name(space) (#292) +- [d2016771](https://github.com/kubevault/operator/commit/d2016771) feat: expose cacert into vault container (#287) +- [e64d4df7](https://github.com/kubevault/operator/commit/e64d4df7) fix: unify some tabs/spaces (#333) +- [3bbe2035](https://github.com/kubevault/operator/commit/3bbe2035) feat: bump vault/sdk (#332) +- [3e26ad02](https://github.com/kubevault/operator/commit/3e26ad02) Add auth ldap users/groups/oidc support (#269) +- [8709dae0](https://github.com/kubevault/operator/commit/8709dae0) AppRole support (#266) +- [9693a2f1](https://github.com/kubevault/operator/commit/9693a2f1) Update Kubernetes v1.18.9 dependencies (#328) +- [f5e532bc](https://github.com/kubevault/operator/commit/f5e532bc) Add support for providing custom readiness probe to vault container (#331) +- [e64d588e](https://github.com/kubevault/operator/commit/e64d588e) Update repository config (#330) +- [4aba3771](https://github.com/kubevault/operator/commit/4aba3771) Update repository config (#329) +- [439739c0](https://github.com/kubevault/operator/commit/439739c0) Update Kubernetes v1.18.9 dependencies (#327) +- [b4cb94d9](https://github.com/kubevault/operator/commit/b4cb94d9) Update repository config (#326) +- [6499483e](https://github.com/kubevault/operator/commit/6499483e) Update Kubernetes v1.18.9 dependencies (#325) +- [e9a7f535](https://github.com/kubevault/operator/commit/e9a7f535) Update Kubernetes v1.18.9 dependencies (#324) +- [1694a955](https://github.com/kubevault/operator/commit/1694a955) Update repository config (#323) +- [42267151](https://github.com/kubevault/operator/commit/42267151) Update Kubernetes v1.18.9 dependencies (#322) +- [9a99e8ac](https://github.com/kubevault/operator/commit/9a99e8ac) Update Kubernetes v1.18.9 dependencies (#320) +- [e4d9e635](https://github.com/kubevault/operator/commit/e4d9e635) Update Kubernetes v1.18.9 dependencies (#319) +- [c733f5c0](https://github.com/kubevault/operator/commit/c733f5c0) Update Kubernetes v1.18.9 dependencies (#318) +- [72084fb8](https://github.com/kubevault/operator/commit/72084fb8) Update Kubernetes v1.18.9 dependencies (#316) +- [c768168a](https://github.com/kubevault/operator/commit/c768168a) Update Kubernetes v1.18.9 dependencies (#315) +- [38577f01](https://github.com/kubevault/operator/commit/38577f01) Update Kubernetes v1.18.9 dependencies (#314) +- [bdfb38b5](https://github.com/kubevault/operator/commit/bdfb38b5) Update Kubernetes v1.18.9 dependencies (#313) +- [b46a651f](https://github.com/kubevault/operator/commit/b46a651f) Update repository config (#312) +- [51ba0a04](https://github.com/kubevault/operator/commit/51ba0a04) Update repository config (#311) +- [60cfdc68](https://github.com/kubevault/operator/commit/60cfdc68) Update Kubernetes v1.18.9 dependencies (#309) +- [9e4a58a8](https://github.com/kubevault/operator/commit/9e4a58a8) Publish docker images to ghcr.io (#310) +- [71e4ac48](https://github.com/kubevault/operator/commit/71e4ac48) Update repository config (#308) +- [7d63715d](https://github.com/kubevault/operator/commit/7d63715d) Update Kubernetes v1.18.9 dependencies (#307) +- [95560663](https://github.com/kubevault/operator/commit/95560663) feat: allow imagePullPolicy in server definition (#289) +- [559c59b3](https://github.com/kubevault/operator/commit/559c59b3) vault: add more env (#284) +- [b480b9fb](https://github.com/kubevault/operator/commit/b480b9fb) feat: refactor of big if/elif (#285) +- [2feb7a64](https://github.com/kubevault/operator/commit/2feb7a64) fix: conform to Kubernetes TLS key naming convention (#278) +- [bec8bb5d](https://github.com/kubevault/operator/commit/bec8bb5d) fix: typo in package name (#280) +- [ad8ba4f5](https://github.com/kubevault/operator/commit/ad8ba4f5) fix: typo (#290) +- [3ada572a](https://github.com/kubevault/operator/commit/3ada572a) Update Kubernetes v1.18.9 dependencies (#305) +- [d832cef4](https://github.com/kubevault/operator/commit/d832cef4) Update Kubernetes v1.18.9 dependencies (#304) +- [fd58a720](https://github.com/kubevault/operator/commit/fd58a720) Update repository config (#303) +- [dc428bb5](https://github.com/kubevault/operator/commit/dc428bb5) Update repository config (#302) +- [a281c7be](https://github.com/kubevault/operator/commit/a281c7be) Update Kubernetes v1.18.9 dependencies (#301) +- [304bd4bc](https://github.com/kubevault/operator/commit/304bd4bc) Update Kubernetes v1.18.3 dependencies (#300) +- [2012acbb](https://github.com/kubevault/operator/commit/2012acbb) Update Kubernetes v1.18.3 dependencies (#299) +- [4c02e68b](https://github.com/kubevault/operator/commit/4c02e68b) Update Kubernetes v1.18.3 dependencies (#298) +- [1082eec3](https://github.com/kubevault/operator/commit/1082eec3) Update Kubernetes v1.18.3 dependencies (#297) +- [961720bf](https://github.com/kubevault/operator/commit/961720bf) Update Kubernetes v1.18.3 dependencies (#296) +- [ddf7e176](https://github.com/kubevault/operator/commit/ddf7e176) Update Kubernetes v1.18.3 dependencies (#295) +- [2381604f](https://github.com/kubevault/operator/commit/2381604f) Update Kubernetes v1.18.3 dependencies (#293) +- [09aecb6c](https://github.com/kubevault/operator/commit/09aecb6c) Update Kubernetes v1.18.3 dependencies (#291) +- [abdd7c58](https://github.com/kubevault/operator/commit/abdd7c58) Update Kubernetes v1.18.3 dependencies (#288) +- [e2e2e49b](https://github.com/kubevault/operator/commit/e2e2e49b) Allow configuring k8s version in e2e tests (#283) +- [f0dd2069](https://github.com/kubevault/operator/commit/f0dd2069) Update to Kubernetes v1.18.3 (#281) +- [e86d96fa](https://github.com/kubevault/operator/commit/e86d96fa) Trigger e2e tests on /ok-to-test command (#277) +- [bedc14da](https://github.com/kubevault/operator/commit/bedc14da) Update to Kubernetes v1.18.3 (#276) +- [f4bb52b7](https://github.com/kubevault/operator/commit/f4bb52b7) Update to Kubernetes v1.18.3 (#275) +- [01289e5c](https://github.com/kubevault/operator/commit/01289e5c) Remove infinite loops from controllers (#274) +- [ed9e4687](https://github.com/kubevault/operator/commit/ed9e4687) Update cloud credentials for e2e tests (#265) +- [a194fec7](https://github.com/kubevault/operator/commit/a194fec7) Update to Kubernetes v1.18.3 (#273) +- [80ddfc5b](https://github.com/kubevault/operator/commit/80ddfc5b) Update ci.yml +- [b2878d97](https://github.com/kubevault/operator/commit/b2878d97) Update workflow name +- [5ba6cfbc](https://github.com/kubevault/operator/commit/5ba6cfbc) Add workflow to update docs (#271) +- [184a9c49](https://github.com/kubevault/operator/commit/184a9c49) Update update-release-tracker.sh +- [892fad2d](https://github.com/kubevault/operator/commit/892fad2d) Update update-release-tracker.sh +- [399f7635](https://github.com/kubevault/operator/commit/399f7635) Add script to update release tracker on pr merge (#270) +- [23e10ff4](https://github.com/kubevault/operator/commit/23e10ff4) Update .kodiak.toml +- [cb835798](https://github.com/kubevault/operator/commit/cb835798) Update to Kubernetes v1.18.3 (#268) +- [92f8164c](https://github.com/kubevault/operator/commit/92f8164c) Use updated TransformSecret helpers +- [286d641f](https://github.com/kubevault/operator/commit/286d641f) Update to Kubernetes v1.18.3 +- [10debf74](https://github.com/kubevault/operator/commit/10debf74) Create .kodiak.toml +- [35355863](https://github.com/kubevault/operator/commit/35355863) Merge pull request #263 from kubevault/x7 +- [d76d8a10](https://github.com/kubevault/operator/commit/d76d8a10) Generate both v1beta1 and v1 CRD YAML +- [991c9c28](https://github.com/kubevault/operator/commit/991c9c28) Fix unit tests +- [b817c589](https://github.com/kubevault/operator/commit/b817c589) Fix linter warnings +- [8a244c09](https://github.com/kubevault/operator/commit/8a244c09) Pass context to test methods +- [50ee8778](https://github.com/kubevault/operator/commit/50ee8778) Merge status conditions +- [9e4f5a8b](https://github.com/kubevault/operator/commit/9e4f5a8b) Pass context and rework status updates +- [bdb39d0d](https://github.com/kubevault/operator/commit/bdb39d0d) Update to Kubernetes v1.18.3 +- [4e709413](https://github.com/kubevault/operator/commit/4e709413) Use standard conditions from kmodules (#261) +- [9b92484b](https://github.com/kubevault/operator/commit/9b92484b) Fix Update***Status() helper methods (#260) +- [9181770b](https://github.com/kubevault/operator/commit/9181770b) Update crazy-max/ghaction-docker-buildx flag +- [3c4e3ce1](https://github.com/kubevault/operator/commit/3c4e3ce1) Use recommended kubernetes app labels (#259) +- [36101fcc](https://github.com/kubevault/operator/commit/36101fcc) Update .env.example +- [c754cb73](https://github.com/kubevault/operator/commit/c754cb73) Add Enum markers to api types +- [5c25bc82](https://github.com/kubevault/operator/commit/5c25bc82) Trigger the workflow on push or pull request +- [48f678d5](https://github.com/kubevault/operator/commit/48f678d5) Use updated operator labels in e2e tests +- [c3e6caf1](https://github.com/kubevault/operator/commit/c3e6caf1) Use kubectl 1.17 in CI (#256) +- [149dba20](https://github.com/kubevault/operator/commit/149dba20) Pass image pull secrets to helm chart +- [e73e1afe](https://github.com/kubevault/operator/commit/e73e1afe) Add license scan report and status (#255) +- [ffe6051a](https://github.com/kubevault/operator/commit/ffe6051a) Update README.md +- [71c0a99f](https://github.com/kubevault/operator/commit/71c0a99f) Update CHANGELOG.md + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.4.0](https://github.com/kubevault/unsealer/releases/tag/v0.4.0) + +- [080fb196](https://github.com/kubevault/unsealer/commit/080fb196) Disable local ca jwt when using k8s auth (#98) +- [cf5ab3ad](https://github.com/kubevault/unsealer/commit/cf5ab3ad) Update dependencies (#97) +- [63103de9](https://github.com/kubevault/unsealer/commit/63103de9) Update dependencies +- [a2a37db2](https://github.com/kubevault/unsealer/commit/a2a37db2) Update README.md +- [d55f5aab](https://github.com/kubevault/unsealer/commit/d55f5aab) Add support for raft storage backend replication (#96) +- [10bbf517](https://github.com/kubevault/unsealer/commit/10bbf517) Use kglog helper +- [4d8f85f4](https://github.com/kubevault/unsealer/commit/4d8f85f4) Use klog/v2 +- [9bab3930](https://github.com/kubevault/unsealer/commit/9bab3930) Use Kubernetes v1.21.0 toolchain (#95) +- [1bcabfac](https://github.com/kubevault/unsealer/commit/1bcabfac) Use Kubernetes v1.21.0 toolchain (#94) +- [21a34b85](https://github.com/kubevault/unsealer/commit/21a34b85) Use Kubernetes v1.21.0 toolchain (#93) +- [bb75f07b](https://github.com/kubevault/unsealer/commit/bb75f07b) Use Kubernetes v1.21.0 toolchain (#92) +- [d0c86418](https://github.com/kubevault/unsealer/commit/d0c86418) Use Kubernetes v1.21.0 toolchain (#91) +- [6e67d3ff](https://github.com/kubevault/unsealer/commit/6e67d3ff) Use Kubernetes v1.21.0 toolchain (#90) +- [e1a05d0c](https://github.com/kubevault/unsealer/commit/e1a05d0c) Update Kubernetes toolchain to v1.21.0 (#89) +- [c5cc88e4](https://github.com/kubevault/unsealer/commit/c5cc88e4) Update repository config (#88) +- [ab0dad7a](https://github.com/kubevault/unsealer/commit/ab0dad7a) Update repository config (#87) +- [8c6c678f](https://github.com/kubevault/unsealer/commit/8c6c678f) Update Kubernetes v1.18.9 dependencies (#86) +- [c7adc826](https://github.com/kubevault/unsealer/commit/c7adc826) Update repository config (#85) +- [e813d23b](https://github.com/kubevault/unsealer/commit/e813d23b) Use AppsCode Community License (#84) +- [ea3f3b65](https://github.com/kubevault/unsealer/commit/ea3f3b65) feat: refactor the loop for readability (#49) +- [4a8d05b6](https://github.com/kubevault/unsealer/commit/4a8d05b6) Various fixes (#47) +- [5547d737](https://github.com/kubevault/unsealer/commit/5547d737) Update Kubernetes v1.18.9 dependencies (#83) +- [f7439b43](https://github.com/kubevault/unsealer/commit/f7439b43) Update repository config (#82) +- [bcbe7969](https://github.com/kubevault/unsealer/commit/bcbe7969) Update repository config (#81) +- [f239d8f6](https://github.com/kubevault/unsealer/commit/f239d8f6) Update Kubernetes v1.18.9 dependencies (#80) +- [df1b0aed](https://github.com/kubevault/unsealer/commit/df1b0aed) Update Kubernetes v1.18.9 dependencies (#79) +- [3783e69d](https://github.com/kubevault/unsealer/commit/3783e69d) Update Kubernetes v1.18.9 dependencies (#78) +- [b17d52d2](https://github.com/kubevault/unsealer/commit/b17d52d2) Update Kubernetes v1.18.9 dependencies (#77) +- [1170ebd3](https://github.com/kubevault/unsealer/commit/1170ebd3) Update Kubernetes v1.18.9 dependencies (#76) +- [f106f149](https://github.com/kubevault/unsealer/commit/f106f149) Update Kubernetes v1.18.9 dependencies (#75) +- [bdb094fa](https://github.com/kubevault/unsealer/commit/bdb094fa) Update Kubernetes v1.18.9 dependencies (#74) +- [a2bb9f44](https://github.com/kubevault/unsealer/commit/a2bb9f44) Update Kubernetes v1.18.9 dependencies (#73) +- [a3fd2449](https://github.com/kubevault/unsealer/commit/a3fd2449) Update Kubernetes v1.18.9 dependencies (#71) +- [c5cb00f4](https://github.com/kubevault/unsealer/commit/c5cb00f4) Update Kubernetes v1.18.9 dependencies (#70) +- [cc1ac397](https://github.com/kubevault/unsealer/commit/cc1ac397) Update repository config (#69) +- [00298897](https://github.com/kubevault/unsealer/commit/00298897) Update Kubernetes v1.18.9 dependencies (#68) +- [8a3ef78d](https://github.com/kubevault/unsealer/commit/8a3ef78d) Publish docker images to ghcr.io (#67) +- [6c04e8b0](https://github.com/kubevault/unsealer/commit/6c04e8b0) Update repository config (#66) +- [9dd21130](https://github.com/kubevault/unsealer/commit/9dd21130) Update Kubernetes v1.18.9 dependencies (#65) +- [3ed6d399](https://github.com/kubevault/unsealer/commit/3ed6d399) Update Kubernetes v1.18.9 dependencies (#64) +- [f4579f60](https://github.com/kubevault/unsealer/commit/f4579f60) Update repository config (#63) +- [f646b9f0](https://github.com/kubevault/unsealer/commit/f646b9f0) Update repository config (#62) +- [c9b1207a](https://github.com/kubevault/unsealer/commit/c9b1207a) Update Kubernetes v1.18.9 dependencies (#61) +- [79c5d2c7](https://github.com/kubevault/unsealer/commit/79c5d2c7) Update Kubernetes v1.18.3 dependencies (#60) +- [19259100](https://github.com/kubevault/unsealer/commit/19259100) Update Kubernetes v1.18.3 dependencies (#59) +- [8f729bd8](https://github.com/kubevault/unsealer/commit/8f729bd8) Update Kubernetes v1.18.3 dependencies (#58) +- [e5b7cf73](https://github.com/kubevault/unsealer/commit/e5b7cf73) Update Kubernetes v1.18.3 dependencies (#57) +- [62d5afa7](https://github.com/kubevault/unsealer/commit/62d5afa7) Update Kubernetes v1.18.3 dependencies (#56) +- [78f48c7b](https://github.com/kubevault/unsealer/commit/78f48c7b) Update Kubernetes v1.18.3 dependencies (#55) +- [d6d6d527](https://github.com/kubevault/unsealer/commit/d6d6d527) Update Kubernetes v1.18.3 dependencies (#54) +- [164f2ac9](https://github.com/kubevault/unsealer/commit/164f2ac9) Update Kubernetes v1.18.3 dependencies (#53) +- [9cd9fe48](https://github.com/kubevault/unsealer/commit/9cd9fe48) Update Kubernetes v1.18.3 dependencies (#52) +- [cba7de70](https://github.com/kubevault/unsealer/commit/cba7de70) Update Kubernetes v1.18.3 dependencies (#51) +- [2142fc54](https://github.com/kubevault/unsealer/commit/2142fc54) Update Kubernetes v1.18.3 dependencies (#50) +- [4d9e6dee](https://github.com/kubevault/unsealer/commit/4d9e6dee) Update Kubernetes v1.18.3 dependencies (#48) +- [33e318b1](https://github.com/kubevault/unsealer/commit/33e318b1) Update to Kubernetes v1.18.3 (#45) +- [74e1fe2e](https://github.com/kubevault/unsealer/commit/74e1fe2e) Update to Kubernetes v1.18.3 (#44) +- [8a0107cb](https://github.com/kubevault/unsealer/commit/8a0107cb) Update to Kubernetes v1.18.3 (#43) +- [a9f2b9a9](https://github.com/kubevault/unsealer/commit/a9f2b9a9) Update to Kubernetes v1.18.3 (#42) +- [e9a9c478](https://github.com/kubevault/unsealer/commit/e9a9c478) Add workflow to update docs (#41) +- [9d14df87](https://github.com/kubevault/unsealer/commit/9d14df87) Update update-release-tracker.sh +- [a3fcc93e](https://github.com/kubevault/unsealer/commit/a3fcc93e) Update update-release-tracker.sh +- [082d563a](https://github.com/kubevault/unsealer/commit/082d563a) Add script to update release tracker on pr merge (#40) +- [a34a3223](https://github.com/kubevault/unsealer/commit/a34a3223) Update .kodiak.toml +- [9dec2281](https://github.com/kubevault/unsealer/commit/9dec2281) Update to Kubernetes v1.18.3 (#39) +- [a14619ed](https://github.com/kubevault/unsealer/commit/a14619ed) Update to Kubernetes v1.18.3 +- [d75b330f](https://github.com/kubevault/unsealer/commit/d75b330f) Create .kodiak.toml +- [25f62d13](https://github.com/kubevault/unsealer/commit/25f62d13) Create draft release from GitHub action (#38) +- [6f034ad0](https://github.com/kubevault/unsealer/commit/6f034ad0) Update to Kubernetes v1.18.3 (#37) +- [46026b28](https://github.com/kubevault/unsealer/commit/46026b28) Trigger the workflow on push or pull request +- [d64ec4e8](https://github.com/kubevault/unsealer/commit/d64ec4e8) Update CHANGELOG.md + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2021.09.27.md b/content/docs/v2025.11.21/CHANGELOG-v2021.09.27.md new file mode 100644 index 000000000..5474a351a --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2021.09.27.md @@ -0,0 +1,111 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2021.09.27 + name: Changelog-v2021.09.27 + parent: welcome + weight: 20210927 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2021.09.27/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2021.09.27/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2021.09.27 (2021-09-27) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.5.0](https://github.com/kubevault/apimachinery/releases/tag/v0.5.0) + +- [8dc3a9f4](https://github.com/kubevault/apimachinery/commit/8dc3a9f4) Add support for SecretRoleBinding CRD (#31) +- [d97bec7d](https://github.com/kubevault/apimachinery/commit/d97bec7d) Update SecretEgnine helper methods (#30) +- [98e1db0b](https://github.com/kubevault/apimachinery/commit/98e1db0b) Log warning if Community License is used with non-demo namespace (#29) +- [d2e0997d](https://github.com/kubevault/apimachinery/commit/d2e0997d) Redesign secret engine crds for self-service mode (#26) +- [7e6e3086](https://github.com/kubevault/apimachinery/commit/7e6e3086) Update repository config (#27) +- [34f98762](https://github.com/kubevault/apimachinery/commit/34f98762) Update dependencies (#25) +- [2deacced](https://github.com/kubevault/apimachinery/commit/2deacced) Update dependencies (#24) +- [19bbdbb1](https://github.com/kubevault/apimachinery/commit/19bbdbb1) Update dependencies (#23) +- [9d6b8fcd](https://github.com/kubevault/apimachinery/commit/9d6b8fcd) Update dependencies (#22) +- [13c9a6d4](https://github.com/kubevault/apimachinery/commit/13c9a6d4) Update repository config (#21) +- [4dfb3d8d](https://github.com/kubevault/apimachinery/commit/4dfb3d8d) Update repository config (#20) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.5.0](https://github.com/kubevault/cli/releases/tag/v0.5.0) + +- [1ed8475](https://github.com/kubevault/cli/commit/1ed8475) Prepare for release v0.5.0 (#128) +- [d2c65bb](https://github.com/kubevault/cli/commit/d2c65bb) Add support for SecretAccessRequest approval or denial (#125) +- [317a8b4](https://github.com/kubevault/cli/commit/317a8b4) Update dependencies (#126) +- [d652e30](https://github.com/kubevault/cli/commit/d652e30) Update dependencies (#124) +- [65ea792](https://github.com/kubevault/cli/commit/65ea792) Update repository config (#123) +- [a92fa68](https://github.com/kubevault/cli/commit/a92fa68) Update dependencies (#122) +- [ee676a6](https://github.com/kubevault/cli/commit/ee676a6) Update dependencies (#121) +- [12a46f3](https://github.com/kubevault/cli/commit/12a46f3) Update dependencies (#120) +- [d9bd71a](https://github.com/kubevault/cli/commit/d9bd71a) Update dependencies (#119) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2021.09.27](https://github.com/kubevault/installer/releases/tag/v2021.09.27) + +- [aeb3345](https://github.com/kubevault/installer/commit/aeb3345) Prepare for release v2021.09.27 (#130) +- [ffe303a](https://github.com/kubevault/installer/commit/ffe303a) Add support for Vault v1.8.2 (#129) +- [4f5bff4](https://github.com/kubevault/installer/commit/4f5bff4) Redesign secret engine crds for self-service mode (#127) +- [9d0296f](https://github.com/kubevault/installer/commit/9d0296f) Log warning if Community License is used with non-demo namespace (#128) +- [c47f4d3](https://github.com/kubevault/installer/commit/c47f4d3) Update dependencies (#126) +- [f6511e7](https://github.com/kubevault/installer/commit/f6511e7) Update repository config (#125) +- [3e1b217](https://github.com/kubevault/installer/commit/3e1b217) Update dependencies (#124) +- [fdfceb0](https://github.com/kubevault/installer/commit/fdfceb0) Update dependencies (#123) +- [2c428d6](https://github.com/kubevault/installer/commit/2c428d6) Update dependencies (#122) +- [dfaa322](https://github.com/kubevault/installer/commit/dfaa322) Update repository config (#121) +- [9dfd255](https://github.com/kubevault/installer/commit/9dfd255) Update repository config (#120) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.5.0](https://github.com/kubevault/operator/releases/tag/v0.5.0) + +- [1217e228](https://github.com/kubevault/operator/commit/1217e228) Prepare for release v0.5.0 (#24) +- [f4c86dfb](https://github.com/kubevault/operator/commit/f4c86dfb) Add support for SecretRoleBinding controller (#23) +- [58b39012](https://github.com/kubevault/operator/commit/58b39012) Redesign secret engine controllers for self-service mode (#19) +- [7895759b](https://github.com/kubevault/operator/commit/7895759b) Update dependencies (#20) +- [a70cfbc5](https://github.com/kubevault/operator/commit/a70cfbc5) Update repository config (#17) +- [1ec90fe0](https://github.com/kubevault/operator/commit/1ec90fe0) Update dependencies (#18) +- [f244a0b6](https://github.com/kubevault/operator/commit/f244a0b6) Update dependencies (#16) +- [a1a8f5d7](https://github.com/kubevault/operator/commit/a1a8f5d7) Restrict to demo namespace for Community Edition (#15) +- [c48266d8](https://github.com/kubevault/operator/commit/c48266d8) Update repository config (#14) +- [930f0245](https://github.com/kubevault/operator/commit/930f0245) Update repository config (#13) +- [ddd838a2](https://github.com/kubevault/operator/commit/ddd838a2) Update repository config (#11) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.5.0](https://github.com/kubevault/unsealer/releases/tag/v0.5.0) + +- [8bcfdf58](https://github.com/kubevault/unsealer/commit/8bcfdf58) Log warning if Community License is used with non-demo namespace (#105) +- [e6c69d86](https://github.com/kubevault/unsealer/commit/e6c69d86) Update dependencies (#104) +- [a27f954a](https://github.com/kubevault/unsealer/commit/a27f954a) Update repository config (#103) +- [1e2c9f1f](https://github.com/kubevault/unsealer/commit/1e2c9f1f) Update dependencies (#102) +- [694b1f39](https://github.com/kubevault/unsealer/commit/694b1f39) Update dependencies (#101) +- [7448e6b3](https://github.com/kubevault/unsealer/commit/7448e6b3) Update dependencies (#100) +- [17da6e49](https://github.com/kubevault/unsealer/commit/17da6e49) Update repository config (#99) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2021.10.11.md b/content/docs/v2025.11.21/CHANGELOG-v2021.10.11.md new file mode 100644 index 000000000..7ab32224a --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2021.10.11.md @@ -0,0 +1,91 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2021.10.11 + name: Changelog-v2021.10.11 + parent: welcome + weight: 20211011 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2021.10.11/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2021.10.11/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2021.10.11 (2021-10-09) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.5.1](https://github.com/kubevault/apimachinery/releases/tag/v0.5.1) + +- [311cc741](https://github.com/kubevault/apimachinery/commit/311cc741) Fix jwt-go security vulnerability (#36) +- [6857c738](https://github.com/kubevault/apimachinery/commit/6857c738) Fix jwt-go security vulnerability (#35) +- [90b49fc8](https://github.com/kubevault/apimachinery/commit/90b49fc8) Update dependencies to publish SiteInfo (#34) +- [11f1fc54](https://github.com/kubevault/apimachinery/commit/11f1fc54) Update dependencies to publish SiteInfo (#33) +- [3f0dfa49](https://github.com/kubevault/apimachinery/commit/3f0dfa49) Update repository config (#32) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.5.1](https://github.com/kubevault/cli/releases/tag/v0.5.1) + +- [5b920e6](https://github.com/kubevault/cli/commit/5b920e6) Prepare for release v0.5.1 (#135) +- [fc8b65e](https://github.com/kubevault/cli/commit/fc8b65e) Fix jwt-go security vulnerability (#133) +- [cf732f0](https://github.com/kubevault/cli/commit/cf732f0) Fix jwt-go security vulnerability (#132) +- [235e696](https://github.com/kubevault/cli/commit/235e696) Use nats.go v1.13.0 (#131) +- [ef9d509](https://github.com/kubevault/cli/commit/ef9d509) Update dependencies to publish SiteInfo (#130) +- [161aab3](https://github.com/kubevault/cli/commit/161aab3) Update dependencies to publish SiteInfo (#129) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2021.10.11](https://github.com/kubevault/installer/releases/tag/v2021.10.11) + +- [55910e0](https://github.com/kubevault/installer/commit/55910e0) Prepare for release v2021.10.11 (#137) +- [12f8428](https://github.com/kubevault/installer/commit/12f8428) Add vault 0.11.5 to catalog (#136) +- [b80479f](https://github.com/kubevault/installer/commit/b80479f) Use kubevault/vault-exporter:v0.1.1 +- [91bbf45](https://github.com/kubevault/installer/commit/91bbf45) Fix jwt-go security vulnerability (#135) +- [fa92ac0](https://github.com/kubevault/installer/commit/fa92ac0) Fix jwt-go security vulnerability (#134) +- [b1688c6](https://github.com/kubevault/installer/commit/b1688c6) Add SiteInfo publisher permission +- [1ac171c](https://github.com/kubevault/installer/commit/1ac171c) Update dependencies to publish SiteInfo (#133) +- [4dd5e18](https://github.com/kubevault/installer/commit/4dd5e18) Add kubevault-metrics chart (#132) +- [275c39d](https://github.com/kubevault/installer/commit/275c39d) Update repository config (#131) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.5.1](https://github.com/kubevault/operator/releases/tag/v0.5.1) + +- [2d051c00](https://github.com/kubevault/operator/commit/2d051c00) Prepare for release v0.5.1 (#29) +- [288a34b1](https://github.com/kubevault/operator/commit/288a34b1) Fix jwt-go security vulnerability (#28) +- [afbd65b7](https://github.com/kubevault/operator/commit/afbd65b7) Use nats.go v1.13.0 (#27) +- [8d808837](https://github.com/kubevault/operator/commit/8d808837) Setup SiteInfo publisher (#26) +- [4fa90b65](https://github.com/kubevault/operator/commit/4fa90b65) Update dependencies to publish SiteInfo (#25) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.5.1](https://github.com/kubevault/unsealer/releases/tag/v0.5.1) + +- [63a431ab](https://github.com/kubevault/unsealer/commit/63a431ab) Fix jwt-go security vulnerability (#109) +- [2449ab5d](https://github.com/kubevault/unsealer/commit/2449ab5d) Fix jwt-go security vulnerability (#108) +- [ae44d44a](https://github.com/kubevault/unsealer/commit/ae44d44a) Update dependencies to publish SiteInfo (#107) +- [e310123c](https://github.com/kubevault/unsealer/commit/e310123c) Update repository config (#106) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2022.01.11.md b/content/docs/v2025.11.21/CHANGELOG-v2022.01.11.md new file mode 100644 index 000000000..c156e8657 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2022.01.11.md @@ -0,0 +1,97 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2022.01.11 + name: Changelog-v2022.01.11 + parent: welcome + weight: 20220111 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2022.01.11/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2022.01.11/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2022.01.11 (2022-01-11) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.6.0](https://github.com/kubevault/apimachinery/releases/tag/v0.6.0) + +- [2fa206cc](https://github.com/kubevault/apimachinery/commit/2fa206cc) Add support for clusterID and sAccessReq phase (#39) +- [51ba1dca](https://github.com/kubevault/apimachinery/commit/51ba1dca) Update repository config (#42) +- [9de92d2a](https://github.com/kubevault/apimachinery/commit/9de92d2a) Update Makefile for controller-tools@v0.7.0 +- [3889ec70](https://github.com/kubevault/apimachinery/commit/3889ec70) Update repository config (#41) +- [2a9d350c](https://github.com/kubevault/apimachinery/commit/2a9d350c) Update dependencies (#40) +- [3aba09bb](https://github.com/kubevault/apimachinery/commit/3aba09bb) Fix satori/go.uuid security vulnerability (#37) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.6.0](https://github.com/kubevault/cli/releases/tag/v0.6.0) + +- [ba4befc](https://github.com/kubevault/cli/commit/ba4befc) Prepare for release v0.6.0 (#140) +- [8e0a33b](https://github.com/kubevault/cli/commit/8e0a33b) Add support for --vault-ca-cert-path flag (#139) +- [0117b31](https://github.com/kubevault/cli/commit/0117b31) Add support for Generate, Revoke command (#138) +- [6214e4c](https://github.com/kubevault/cli/commit/6214e4c) Add support for get-root-token command (#134) +- [9781501](https://github.com/kubevault/cli/commit/9781501) Update dependencies (#137) +- [70743de](https://github.com/kubevault/cli/commit/70743de) Fix satori/go.uuid security vulnerability (#136) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2022.01.11](https://github.com/kubevault/installer/releases/tag/v2022.01.11) + +- [d8ff86b](https://github.com/kubevault/installer/commit/d8ff86b) Prepare for release v2022.01.11 (#144) +- [5370acd](https://github.com/kubevault/installer/commit/5370acd) Add support for vault:1.9.2 (#143) +- [ff98bf5](https://github.com/kubevault/installer/commit/ff98bf5) Update repository config (#142) +- [d5b4bb3](https://github.com/kubevault/installer/commit/d5b4bb3) Add permissions for cert-manager CRs (#141) +- [57e4d3c](https://github.com/kubevault/installer/commit/57e4d3c) Update repository config (#140) +- [90b3051](https://github.com/kubevault/installer/commit/90b3051) Update dependencies (#139) +- [665e185](https://github.com/kubevault/installer/commit/665e185) Fix satori/go.uuid security vulnerability (#138) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.6.0](https://github.com/kubevault/operator/releases/tag/v0.6.0) + +- [24359467](https://github.com/kubevault/operator/commit/24359467) Prepare for release v0.6.0 (#42) +- [b7ebc457](https://github.com/kubevault/operator/commit/b7ebc457) Reworks on operator codebase (#37) +- [b8121081](https://github.com/kubevault/operator/commit/b8121081) Run trivy scanner (#41) +- [cc00d749](https://github.com/kubevault/operator/commit/cc00d749) Update repository config (#38) +- [18307b26](https://github.com/kubevault/operator/commit/18307b26) Remove repository directories before cloning them in CI (#40) +- [ad2a4d1a](https://github.com/kubevault/operator/commit/ad2a4d1a) Delete existing cluster in CI +- [6e25e142](https://github.com/kubevault/operator/commit/6e25e142) Always run e2e tests (#39) +- [3bd270c6](https://github.com/kubevault/operator/commit/3bd270c6) Update repository config (#34) +- [ccf31742](https://github.com/kubevault/operator/commit/ccf31742) Remove global variable for preconditions (#33) +- [4497bf40](https://github.com/kubevault/operator/commit/4497bf40) Update dependencies (#31) +- [37b6030a](https://github.com/kubevault/operator/commit/37b6030a) Fix satori/go.uuid security vulnerability (#30) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.6.0](https://github.com/kubevault/unsealer/releases/tag/v0.6.0) + +- [e4382c74](https://github.com/kubevault/unsealer/commit/e4382c74) Add cluster-name flag (#114) +- [e4a7e133](https://github.com/kubevault/unsealer/commit/e4a7e133) Fix unseal keys conflict (#113) +- [b04cc1a6](https://github.com/kubevault/unsealer/commit/b04cc1a6) Update repository config (#112) +- [e0f4000b](https://github.com/kubevault/unsealer/commit/e0f4000b) Update dependencies (#111) +- [629984be](https://github.com/kubevault/unsealer/commit/629984be) Fix satori/go.uuid security vulnerability (#110) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2022.02.22.md b/content/docs/v2025.11.21/CHANGELOG-v2022.02.22.md new file mode 100644 index 000000000..8809f3cda --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2022.02.22.md @@ -0,0 +1,87 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2022.02.22 + name: Changelog-v2022.02.22 + parent: welcome + weight: 20220222 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2022.02.22/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2022.02.22/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2022.02.22 (2022-02-18) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.7.0](https://github.com/kubevault/apimachinery/releases/tag/v0.7.0) + +- [1831b006](https://github.com/kubevault/apimachinery/commit/1831b006) Cancel concurrent CI runs for same pr/commit (#46) +- [29e4aefe](https://github.com/kubevault/apimachinery/commit/29e4aefe) Update SiteInfo (#45) +- [6125f9ff](https://github.com/kubevault/apimachinery/commit/6125f9ff) Publish GenericResource (#44) +- [a2ece4cc](https://github.com/kubevault/apimachinery/commit/a2ece4cc) Update repository config (#43) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.7.0](https://github.com/kubevault/cli/releases/tag/v0.7.0) + +- [53c42c4](https://github.com/kubevault/cli/commit/53c42c4) Prepare for release v0.7.0 (#147) +- [d9b7e37](https://github.com/kubevault/cli/commit/d9b7e37) Cancel concurrent CI runs for same pr/commit (#146) +- [4a36f36](https://github.com/kubevault/cli/commit/4a36f36) Update UID generation for GenericResource (#145) +- [5b3984e](https://github.com/kubevault/cli/commit/5b3984e) Update SiteInfo (#144) +- [cfe2193](https://github.com/kubevault/cli/commit/cfe2193) Publish GenericResource (#143) +- [796b9b6](https://github.com/kubevault/cli/commit/796b9b6) Release cli for darwin/arm64 (#142) +- [af8810e](https://github.com/kubevault/cli/commit/af8810e) Add get, set, delete, and list methods for root-token & unseal-keys (#141) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2022.02.22](https://github.com/kubevault/installer/releases/tag/v2022.02.22) + +- [d2d0af7](https://github.com/kubevault/installer/commit/d2d0af7) Prepare for release v2022.02.22 (#151) +- [51e1f6c](https://github.com/kubevault/installer/commit/51e1f6c) Cancel concurrent CI runs for same pr/commit (#150) +- [78c5444](https://github.com/kubevault/installer/commit/78c5444) Update repository config (#149) +- [10a50a5](https://github.com/kubevault/installer/commit/10a50a5) Use well-known os label (#148) +- [642e53e](https://github.com/kubevault/installer/commit/642e53e) Publish GenericResource (#147) +- [5b68f85](https://github.com/kubevault/installer/commit/5b68f85) Update repository config (#146) +- [53a096a](https://github.com/kubevault/installer/commit/53a096a) Add permission to list namespace (#145) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.7.0](https://github.com/kubevault/operator/releases/tag/v0.7.0) + +- [638a2c60](https://github.com/kubevault/operator/commit/638a2c60) Prepare for release v0.7.0 (#49) +- [705a39ea](https://github.com/kubevault/operator/commit/705a39ea) Update UID generation for GenericResource (#48) +- [f7bf562f](https://github.com/kubevault/operator/commit/f7bf562f) Update SiteInfo (#47) +- [4cc99f5a](https://github.com/kubevault/operator/commit/4cc99f5a) Publish GenericResource (#46) +- [f1d9dee4](https://github.com/kubevault/operator/commit/f1d9dee4) Update repository config (#44) +- [6bc100d3](https://github.com/kubevault/operator/commit/6bc100d3) Fix matchlabels ns list bug (#45) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.7.0](https://github.com/kubevault/unsealer/releases/tag/v0.7.0) + +- [d1e13106](https://github.com/kubevault/unsealer/commit/d1e13106) Publish GenericResource (#115) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2022.06.16.md b/content/docs/v2025.11.21/CHANGELOG-v2022.06.16.md new file mode 100644 index 000000000..1487ea1e5 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2022.06.16.md @@ -0,0 +1,119 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2022.06.16 + name: Changelog-v2022.06.16 + parent: welcome + weight: 20220616 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2022.06.16/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2022.06.16/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2022.06.16 (2022-06-10) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.8.0](https://github.com/kubevault/apimachinery/releases/tag/v0.8.0) + +- [6cbcd6ed](https://github.com/kubevault/apimachinery/commit/6cbcd6ed) Update to k8s 1.24 toolchain (#60) +- [2970666d](https://github.com/kubevault/apimachinery/commit/2970666d) Add support for JWT/OIDC auth method (#58) +- [885da664](https://github.com/kubevault/apimachinery/commit/885da664) Test against Kubernetes 1.24.0 (#59) +- [da0750a7](https://github.com/kubevault/apimachinery/commit/da0750a7) v1alpha2 api conversion (#52) +- [716f6fa7](https://github.com/kubevault/apimachinery/commit/716f6fa7) Use Go 1.18 (#55) +- [831710c9](https://github.com/kubevault/apimachinery/commit/831710c9) Use Go 1.18 (#53) +- [78081ee6](https://github.com/kubevault/apimachinery/commit/78081ee6) Add kubevault.com/v1alpha2 api (#50) +- [33b160d7](https://github.com/kubevault/apimachinery/commit/33b160d7) make fmt (#48) +- [6c189049](https://github.com/kubevault/apimachinery/commit/6c189049) Add Kind() methods (#47) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.8.0](https://github.com/kubevault/cli/releases/tag/v0.8.0) + +- [e41268d7](https://github.com/kubevault/cli/commit/e41268d7) Prepare for release v0.8.0 (#155) +- [2b54317e](https://github.com/kubevault/cli/commit/2b54317e) Update to k8s 1.24 toolchain (#154) +- [b684e2b9](https://github.com/kubevault/cli/commit/b684e2b9) Add v1alpha2 changes (#153) +- [c338ec82](https://github.com/kubevault/cli/commit/c338ec82) Use Go 1.18 (#152) +- [60b63920](https://github.com/kubevault/cli/commit/60b63920) Use Go 1.18 (#150) +- [6b7ec5ef](https://github.com/kubevault/cli/commit/6b7ec5ef) make fmt (#149) +- [4e5ce4c9](https://github.com/kubevault/cli/commit/4e5ce4c9) Update UID generation for GenericResource (#148) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2022.06.16](https://github.com/kubevault/installer/releases/tag/v2022.06.16) + +- [43feb59](https://github.com/kubevault/installer/commit/43feb59) Prepare for release v2022.06.16 (#171) +- [b2ac521](https://github.com/kubevault/installer/commit/b2ac521) Update registry templates to support custom default registry (ghcr.io) (#170) +- [0b0c419](https://github.com/kubevault/installer/commit/0b0c419) Don't set tag in values files +- [cd242d6](https://github.com/kubevault/installer/commit/cd242d6) Add support for vault:1.10.3 (#167) +- [530db29](https://github.com/kubevault/installer/commit/530db29) Add secrets-store-reader chart (#169) +- [98e19e5](https://github.com/kubevault/installer/commit/98e19e5) Test against Kubernetes 1.24.0 (#168) +- [f212b1b](https://github.com/kubevault/installer/commit/f212b1b) Get operator tag from .Chart.AppVersion (#166) +- [9db93b4](https://github.com/kubevault/installer/commit/9db93b4) Test against Kubernetes 1.24.0 (#165) +- [f07c0de](https://github.com/kubevault/installer/commit/f07c0de) Test operator monitoring (#164) +- [9f7011e](https://github.com/kubevault/installer/commit/9f7011e) Add apiservice get permission for crd conversion webhook config (#163) +- [1a01910](https://github.com/kubevault/installer/commit/1a01910) Change MY_POD_ env fix to POD_ +- [ce24272](https://github.com/kubevault/installer/commit/ce24272) Clean up monitoring values from chart (#161) +- [3cf0088](https://github.com/kubevault/installer/commit/3cf0088) Remove unimplemented webhook config +- [5937bbc](https://github.com/kubevault/installer/commit/5937bbc) Remove validators.policy.kubevault.com apiservice +- [d3084e5](https://github.com/kubevault/installer/commit/d3084e5) Add webhook & kubevault-operator permission (#160) +- [19e0a9b](https://github.com/kubevault/installer/commit/19e0a9b) Split into operator and webhook chart (#158) +- [2b8b424](https://github.com/kubevault/installer/commit/2b8b424) Use Go 1.18 (#157) +- [0bc3634](https://github.com/kubevault/installer/commit/0bc3634) Use Go 1.18 (#156) +- [e18357e](https://github.com/kubevault/installer/commit/e18357e) make fmt (#154) +- [427e146](https://github.com/kubevault/installer/commit/427e146) Use webhooks suffix for webhook resources (#152) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.8.0](https://github.com/kubevault/operator/releases/tag/v0.8.0) + +- [06ad2e3a](https://github.com/kubevault/operator/commit/06ad2e3a) Prepare for release v0.8.0 (#63) +- [26197fe0](https://github.com/kubevault/operator/commit/26197fe0) Update to k8s 1.24 toolchain (#62) +- [d6f03739](https://github.com/kubevault/operator/commit/d6f03739) Add support for JWT/OIDC auth method, Fix Vault resources sync (#56) +- [58e1cf81](https://github.com/kubevault/operator/commit/58e1cf81) Update ci.yml +- [6cad6340](https://github.com/kubevault/operator/commit/6cad6340) Disable trivy scanner +- [8932662a](https://github.com/kubevault/operator/commit/8932662a) Use CI hosts with label ubuntu-latest +- [28c4829d](https://github.com/kubevault/operator/commit/28c4829d) Test against Kubernetes 1.24.0 (#61) +- [f195aaad](https://github.com/kubevault/operator/commit/f195aaad) Enable CI checks +- [2c14f4d8](https://github.com/kubevault/operator/commit/2c14f4d8) Run e2e tests (#60) +- [0361cecd](https://github.com/kubevault/operator/commit/0361cecd) Fix CI (#59) +- [f225c385](https://github.com/kubevault/operator/commit/f225c385) Introduce separate commands for operator and webhook (#58) +- [935b7ce5](https://github.com/kubevault/operator/commit/935b7ce5) Use sefl-hosted runner (#57) +- [c677d9ae](https://github.com/kubevault/operator/commit/c677d9ae) Use Go 1.18 (#54) +- [90f0ab47](https://github.com/kubevault/operator/commit/90f0ab47) make fmt (#52) +- [17593e4c](https://github.com/kubevault/operator/commit/17593e4c) Use webhooks suffix for webhook resources (#51) +- [41bbd827](https://github.com/kubevault/operator/commit/41bbd827) Cancel concurrent CI runs for same pr/commit (#50) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.8.0](https://github.com/kubevault/unsealer/releases/tag/v0.8.0) + +- [2b05c29b](https://github.com/kubevault/unsealer/commit/2b05c29b) Update to k8s 1.24 toolchain (#120) +- [085df87a](https://github.com/kubevault/unsealer/commit/085df87a) Use Go 1.18 (#119) +- [f70eb944](https://github.com/kubevault/unsealer/commit/f70eb944) Use Go 1.18 (#118) +- [41d67ef4](https://github.com/kubevault/unsealer/commit/41d67ef4) make fmt (#117) +- [7ff0f673](https://github.com/kubevault/unsealer/commit/7ff0f673) Cancel concurrent CI runs for same pr/commit (#116) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2022.09.05-rc.0.md b/content/docs/v2025.11.21/CHANGELOG-v2022.09.05-rc.0.md new file mode 100644 index 000000000..8bcb7ac62 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2022.09.05-rc.0.md @@ -0,0 +1,74 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2022.09.05-rc.0 + name: Changelog-v2022.09.05-rc.0 + parent: welcome + weight: 20220905 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2022.09.05-rc.0/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2022.09.05-rc.0/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2022.09.05-rc.0 (2022-09-06) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.9.0-rc.0](https://github.com/kubevault/apimachinery/releases/tag/v0.9.0-rc.0) + +- [857a5c01](https://github.com/kubevault/apimachinery/commit/857a5c01) Add vault ops-request API (#61) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.9.0-rc.0](https://github.com/kubevault/cli/releases/tag/v0.9.0-rc.0) + +- [a80515e1](https://github.com/kubevault/cli/commit/a80515e1) Prepare for release v0.9.0-rc.0 (#157) +- [932bb02e](https://github.com/kubevault/cli/commit/932bb02e) Add command for generating & rotating vault root token (#156) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2022.09.05-rc.0](https://github.com/kubevault/installer/releases/tag/v2022.09.05-rc.0) + +- [f07cba4](https://github.com/kubevault/installer/commit/f07cba4) Prepare for release v2022.09.05-rc.0 (#175) +- [79473f3](https://github.com/kubevault/installer/commit/79473f3) Add recommendation engine flags & values (#174) +- [9e14119](https://github.com/kubevault/installer/commit/9e14119) Update installer for vault ops-request (#172) +- [1f3e429](https://github.com/kubevault/installer/commit/1f3e429) Add permission for license-proxyserver (#173) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.9.0-rc.0](https://github.com/kubevault/operator/releases/tag/v0.9.0-rc.0) + +- [69442f24](https://github.com/kubevault/operator/commit/69442f24) Prepare for release v0.9.0-rc.0 (#70) +- [b3e7e701](https://github.com/kubevault/operator/commit/b3e7e701) Add recommendation engine for vault server (#68) +- [1264f212](https://github.com/kubevault/operator/commit/1264f212) Add support for RotateTLS and Restart Ops-Request (#66) +- [a7968a97](https://github.com/kubevault/operator/commit/a7968a97) Stop using removed apis in Kubernetes 1.25 (#69) +- [81a8f84f](https://github.com/kubevault/operator/commit/81a8f84f) Acquire license from license-proxyserver if available (#67) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.9.0-rc.0](https://github.com/kubevault/unsealer/releases/tag/v0.9.0-rc.0) + + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2022.09.09.md b/content/docs/v2025.11.21/CHANGELOG-v2022.09.09.md new file mode 100644 index 000000000..69ea0e5a0 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2022.09.09.md @@ -0,0 +1,79 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2022.09.09 + name: Changelog-v2022.09.09 + parent: welcome + weight: 20220909 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2022.09.09/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2022.09.09/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2022.09.09 (2022-09-09) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.9.0](https://github.com/kubevault/apimachinery/releases/tag/v0.9.0) + +- [0c82c982](https://github.com/kubevault/apimachinery/commit/0c82c982) Update offshoot api (#62) +- [857a5c01](https://github.com/kubevault/apimachinery/commit/857a5c01) Add vault ops-request API (#61) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.9.0](https://github.com/kubevault/cli/releases/tag/v0.9.0) + +- [bf9241eb](https://github.com/kubevault/cli/commit/bf9241eb) Prepare for release v0.9.0 (#158) +- [a80515e1](https://github.com/kubevault/cli/commit/a80515e1) Prepare for release v0.9.0-rc.0 (#157) +- [932bb02e](https://github.com/kubevault/cli/commit/932bb02e) Add command for generating & rotating vault root token (#156) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2022.09.09](https://github.com/kubevault/installer/releases/tag/v2022.09.09) + +- [b4d3a6d](https://github.com/kubevault/installer/commit/b4d3a6d) Prepare for release v2022.09.09 (#176) +- [f07cba4](https://github.com/kubevault/installer/commit/f07cba4) Prepare for release v2022.09.05-rc.0 (#175) +- [79473f3](https://github.com/kubevault/installer/commit/79473f3) Add recommendation engine flags & values (#174) +- [9e14119](https://github.com/kubevault/installer/commit/9e14119) Update installer for vault ops-request (#172) +- [1f3e429](https://github.com/kubevault/installer/commit/1f3e429) Add permission for license-proxyserver (#173) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.9.0](https://github.com/kubevault/operator/releases/tag/v0.9.0) + +- [ba6b3387](https://github.com/kubevault/operator/commit/ba6b3387) Prepare for release v0.9.0 (#72) +- [8c6050c5](https://github.com/kubevault/operator/commit/8c6050c5) Use PDB depending on k8s version (#71) +- [69442f24](https://github.com/kubevault/operator/commit/69442f24) Prepare for release v0.9.0-rc.0 (#70) +- [b3e7e701](https://github.com/kubevault/operator/commit/b3e7e701) Add recommendation engine for vault server (#68) +- [1264f212](https://github.com/kubevault/operator/commit/1264f212) Add support for RotateTLS and Restart Ops-Request (#66) +- [a7968a97](https://github.com/kubevault/operator/commit/a7968a97) Stop using removed apis in Kubernetes 1.25 (#69) +- [81a8f84f](https://github.com/kubevault/operator/commit/81a8f84f) Acquire license from license-proxyserver if available (#67) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.9.0](https://github.com/kubevault/unsealer/releases/tag/v0.9.0) + + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2022.09.22.md b/content/docs/v2025.11.21/CHANGELOG-v2022.09.22.md new file mode 100644 index 000000000..638dc5eeb --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2022.09.22.md @@ -0,0 +1,78 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2022.09.22 + name: Changelog-v2022.09.22 + parent: welcome + weight: 20220922 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2022.09.22/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2022.09.22/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2022.09.22 (2022-09-22) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.10.0](https://github.com/kubevault/apimachinery/releases/tag/v0.10.0) + +- [d0491184](https://github.com/kubevault/apimachinery/commit/d0491184) Fix conversion (#63) +- [42a9f95c](https://github.com/kubevault/apimachinery/commit/42a9f95c) Fix K8s version +- [d8e6f760](https://github.com/kubevault/apimachinery/commit/d8e6f760) Use Go 1.19 (#65) +- [7fce2029](https://github.com/kubevault/apimachinery/commit/7fce2029) Use k8s 1.25.1 libs (#64) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.10.0](https://github.com/kubevault/cli/releases/tag/v0.10.0) + +- [5372dba7](https://github.com/kubevault/cli/commit/5372dba7) Prepare for release v0.10.0 (#161) +- [015176a9](https://github.com/kubevault/cli/commit/015176a9) Use Go 1.19 (#160) +- [67ec5d36](https://github.com/kubevault/cli/commit/67ec5d36) Use k8s 1.25.1 libs (#159) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2022.09.22](https://github.com/kubevault/installer/releases/tag/v2022.09.22) + +- [bbbc40a](https://github.com/kubevault/installer/commit/bbbc40a) Prepare for release v2022.09.22 (#180) +- [ca42d02](https://github.com/kubevault/installer/commit/ca42d02) Update crds (#178) +- [f1c6c62](https://github.com/kubevault/installer/commit/f1c6c62) Test against k8s 1.25.0 (#179) +- [bb28027](https://github.com/kubevault/installer/commit/bb28027) Use Go 1.19 (#177) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.10.0](https://github.com/kubevault/operator/releases/tag/v0.10.0) + +- [10e80edb](https://github.com/kubevault/operator/commit/10e80edb) Prepare for release v0.10.0 (#76) +- [4411a557](https://github.com/kubevault/operator/commit/4411a557) Fix Sealed phase calculation (#73) +- [38c5a35b](https://github.com/kubevault/operator/commit/38c5a35b) Use Go 1.19 (#75) +- [bd9e7124](https://github.com/kubevault/operator/commit/bd9e7124) Use k8s 1.25.1 libs (#74) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.10.0](https://github.com/kubevault/unsealer/releases/tag/v0.10.0) + +- [c1711c20](https://github.com/kubevault/unsealer/commit/c1711c20) Use Go 1.19 (#121) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2022.11.30.md b/content/docs/v2025.11.21/CHANGELOG-v2022.11.30.md new file mode 100644 index 000000000..50a185825 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2022.11.30.md @@ -0,0 +1,75 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2022.11.30 + name: Changelog-v2022.11.30 + parent: welcome + weight: 20221130 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2022.11.30/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2022.11.30/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2022.11.30 (2022-11-30) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.11.0](https://github.com/kubevault/apimachinery/releases/tag/v0.11.0) + +- [6d5535a8](https://github.com/kubevault/apimachinery/commit/6d5535a8) Update VaultServerConfig with BackupSecret (#68) +- [e2b451c5](https://github.com/kubevault/apimachinery/commit/e2b451c5) Update testing lib +- [ffe70235](https://github.com/kubevault/apimachinery/commit/ffe70235) Use gomodules.xyz/testing +- [c5e99527](https://github.com/kubevault/apimachinery/commit/c5e99527) Rename ACLTokenSecretName to ACLTokenSecretRef (#67) +- [8b47cc1b](https://github.com/kubevault/apimachinery/commit/8b47cc1b) Test against Kubernetes 1.25.0 (#66) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.11.0](https://github.com/kubevault/cli/releases/tag/v0.11.0) + +- [ec9eba04](https://github.com/kubevault/cli/commit/ec9eba04) Prepare for release v0.11.0 (#164) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2022.11.30](https://github.com/kubevault/installer/releases/tag/v2022.11.30) + +- [fb40772](https://github.com/kubevault/installer/commit/fb40772) Prepare for release v2022.11.30 (#184) +- [2ca1152](https://github.com/kubevault/installer/commit/2ca1152) Add Vault Versions v1.11.5, v1.12.1 (#183) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.11.0](https://github.com/kubevault/operator/releases/tag/v0.11.0) + +- [c2e9a825](https://github.com/kubevault/operator/commit/c2e9a825) Prepare for release v0.11.0 (#81) +- [1ef7298b](https://github.com/kubevault/operator/commit/1ef7298b) Configure Vault Backup (#79) +- [e7da2b32](https://github.com/kubevault/operator/commit/e7da2b32) Acquire license from proxyserver (#80) +- [fbaa897b](https://github.com/kubevault/operator/commit/fbaa897b) Rename ACLTokenSecretName to ACLTokenSecretRef (#78) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.11.0](https://github.com/kubevault/unsealer/releases/tag/v0.11.0) + +- [88f9ae0e](https://github.com/kubevault/unsealer/commit/88f9ae0e) Test against Kubernetes 1.25.0 (#122) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2022.12.09.md b/content/docs/v2025.11.21/CHANGELOG-v2022.12.09.md new file mode 100644 index 000000000..f210bb07c --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2022.12.09.md @@ -0,0 +1,71 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2022.12.09 + name: Changelog-v2022.12.09 + parent: welcome + weight: 20221209 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2022.12.09/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2022.12.09/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2022.12.09 (2022-12-09) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.12.0](https://github.com/kubevault/apimachinery/releases/tag/v0.12.0) + +- [ee1cd930](https://github.com/kubevault/apimachinery/commit/ee1cd930) Add Backend & Unsealer info in AppBinding (#69) +- [6f0b7f16](https://github.com/kubevault/apimachinery/commit/6f0b7f16) Run GH actions on ubuntu-20.04 (#70) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.12.0](https://github.com/kubevault/cli/releases/tag/v0.12.0) + +- [56cc5750](https://github.com/kubevault/cli/commit/56cc5750) Prepare for release v0.12.0 (#166) +- [0ca1aff0](https://github.com/kubevault/cli/commit/0ca1aff0) Run GH actions on ubuntu-20.04 (#165) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2022.12.09](https://github.com/kubevault/installer/releases/tag/v2022.12.09) + +- [df5997d](https://github.com/kubevault/installer/commit/df5997d) Prepare for release v2022.12.09 (#186) +- [a62af67](https://github.com/kubevault/installer/commit/a62af67) Run GH actions on ubuntu-20.04 (#185) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.12.0](https://github.com/kubevault/operator/releases/tag/v0.12.0) + +- [7a55dc9b](https://github.com/kubevault/operator/commit/7a55dc9b) Prepare for release v0.12.0 (#84) +- [2019e0c2](https://github.com/kubevault/operator/commit/2019e0c2) Update AppBinding with Unsealer & Backend info (#82) +- [7c2f651a](https://github.com/kubevault/operator/commit/7c2f651a) Run GH actions on ubuntu-20.04 (#83) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.12.0](https://github.com/kubevault/unsealer/releases/tag/v0.12.0) + + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2022.12.28.md b/content/docs/v2025.11.21/CHANGELOG-v2022.12.28.md new file mode 100644 index 000000000..bf2f80917 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2022.12.28.md @@ -0,0 +1,71 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2022.12.28 + name: Changelog-v2022.12.28 + parent: welcome + weight: 20221228 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2022.12.28/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2022.12.28/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2022.12.28 (2022-12-28) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.13.0](https://github.com/kubevault/apimachinery/releases/tag/v0.13.0) + +- [3e0d8ee9](https://github.com/kubevault/apimachinery/commit/3e0d8ee9) Add Redis Secret Engine APIs (#72) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.13.0](https://github.com/kubevault/cli/releases/tag/v0.13.0) + +- [85d3fa76](https://github.com/kubevault/cli/commit/85d3fa76) Prepare for release v0.13.0 (#169) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2022.12.28](https://github.com/kubevault/installer/releases/tag/v2022.12.28) + +- [6f187f3](https://github.com/kubevault/installer/commit/6f187f3) Prepare for release v2022.12.28 (#188) +- [de77c42](https://github.com/kubevault/installer/commit/de77c42) Add Redis Secret Engine (#187) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.13.0](https://github.com/kubevault/operator/releases/tag/v0.13.0) + +- [1a328fcc](https://github.com/kubevault/operator/commit/1a328fcc) Prepare for release v0.13.0 (#87) +- [5c53d615](https://github.com/kubevault/operator/commit/5c53d615) Update Google Dependency (#88) +- [9d173a3c](https://github.com/kubevault/operator/commit/9d173a3c) Add Redis Secret Engine (#85) +- [f17e68d9](https://github.com/kubevault/operator/commit/f17e68d9) Update dependencies (#86) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.13.0](https://github.com/kubevault/unsealer/releases/tag/v0.13.0) + +- [f8e44cf0](https://github.com/kubevault/unsealer/commit/f8e44cf0) Run GH actions on ubuntu-20.04 (#123) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2023.03.03.md b/content/docs/v2025.11.21/CHANGELOG-v2023.03.03.md new file mode 100644 index 000000000..496f5a3d4 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2023.03.03.md @@ -0,0 +1,81 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2023.03.03 + name: Changelog-v2023.03.03 + parent: welcome + weight: 20230303 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2023.03.03/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2023.03.03/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2023.03.03 (2023-03-03) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.14.0](https://github.com/kubevault/apimachinery/releases/tag/v0.14.0) + +- [d6fde647](https://github.com/kubevault/apimachinery/commit/d6fde647) Some cleanup +- [ed87b314](https://github.com/kubevault/apimachinery/commit/ed87b314) Update wrokflows (Go 1.20, k8s 1.26) (#77) +- [9bd6be24](https://github.com/kubevault/apimachinery/commit/9bd6be24) Mark exported field optional in Version CRD (#74) +- [6e847734](https://github.com/kubevault/apimachinery/commit/6e847734) Update wrokflows (Go 1.20, k8s 1.26) (#75) +- [c64f0bc7](https://github.com/kubevault/apimachinery/commit/c64f0bc7) Use api constants for tls.crt +- [67d27681](https://github.com/kubevault/apimachinery/commit/67d27681) Add Prometheus Monitoring (#73) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.14.0](https://github.com/kubevault/cli/releases/tag/v0.14.0) + +- [d8533125](https://github.com/kubevault/cli/commit/d8533125) Prepare for release v0.14.0 (#172) +- [8b29d08d](https://github.com/kubevault/cli/commit/8b29d08d) Update workflows (Go 1.20, k8s 1.26) (#171) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2023.03.03](https://github.com/kubevault/installer/releases/tag/v2023.03.03) + +- [f346362](https://github.com/kubevault/installer/commit/f346362) Prepare for release v2023.03.03 (#196) +- [8d001ff](https://github.com/kubevault/installer/commit/8d001ff) Update Makefile +- [a14b739](https://github.com/kubevault/installer/commit/a14b739) Add opscenter and grafana-dashboard charts (#194) +- [83a1380](https://github.com/kubevault/installer/commit/83a1380) Pass license to kubevault-webhook-server chart +- [559a94e](https://github.com/kubevault/installer/commit/559a94e) Update workflows (Go 1.20, k8s 1.26) (#193) +- [af49db4](https://github.com/kubevault/installer/commit/af49db4) Add MetricsConfiguration for VaultServer (#190) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.14.0](https://github.com/kubevault/operator/releases/tag/v0.14.0) + +- [564680ca](https://github.com/kubevault/operator/commit/564680ca) Prepare for release v0.14.0 (#92) +- [48131355](https://github.com/kubevault/operator/commit/48131355) Update workflows (Go 1.20, k8s 1.26) (#91) +- [ead6eed7](https://github.com/kubevault/operator/commit/ead6eed7) Add Prometheus Monitoring (#89) +- [add7a1ca](https://github.com/kubevault/operator/commit/add7a1ca) Set registryFQDN to use docker (#90) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.14.0](https://github.com/kubevault/unsealer/releases/tag/v0.14.0) + +- [d609c8e3](https://github.com/kubevault/unsealer/commit/d609c8e3) Update wrokflows (Go 1.20, k8s 1.26) (#126) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2023.05.05.md b/content/docs/v2025.11.21/CHANGELOG-v2023.05.05.md new file mode 100644 index 000000000..d37f9413f --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2023.05.05.md @@ -0,0 +1,88 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2023.05.05 + name: Changelog-v2023.05.05 + parent: welcome + weight: 20230505 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2023.05.05/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2023.05.05/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2023.05.05 (2023-05-05) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.15.0](https://github.com/kubevault/apimachinery/releases/tag/v0.15.0) + +- [9eef185c](https://github.com/kubevault/apimachinery/commit/9eef185c) Add enableServiceLinks to pod spec +- [22ad2d1b](https://github.com/kubevault/apimachinery/commit/22ad2d1b) Test against K8s 1.27.1 (#82) +- [d3e98559](https://github.com/kubevault/apimachinery/commit/d3e98559) Use uid 65534 and test against K8s 1.27.0 (#81) +- [f6a0ef16](https://github.com/kubevault/apimachinery/commit/f6a0ef16) Use ghcr.io/appscode/gengo (#80) +- [00cbce63](https://github.com/kubevault/apimachinery/commit/00cbce63) Use ghcr.io for appscode/golang-dev (#79) +- [8f21c8dd](https://github.com/kubevault/apimachinery/commit/8f21c8dd) Update workflows (Go 1.20, k8s 1.26) (#78) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.15.0](https://github.com/kubevault/cli/releases/tag/v0.15.0) + +- [139070bf](https://github.com/kubevault/cli/commit/139070bf) Prepare for release v0.15.0 (#175) +- [86f87a0a](https://github.com/kubevault/cli/commit/86f87a0a) Use ghcr.io for appscode/golang-dev (#174) +- [ce2d1f90](https://github.com/kubevault/cli/commit/ce2d1f90) Update workflows (Go 1.20, k8s 1.26) (#173) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2023.05.05](https://github.com/kubevault/installer/releases/tag/v2023.05.05) + +- [eb90293](https://github.com/kubevault/installer/commit/eb90293) Prepare for release v2023.05.05 (#202) +- [a43f89a](https://github.com/kubevault/installer/commit/a43f89a) Test against K8s 1.27.1 (#201) +- [10c283c](https://github.com/kubevault/installer/commit/10c283c) Use uid 65534 and test against K8s 1.27.0 (#200) +- [a07923e](https://github.com/kubevault/installer/commit/a07923e) Use ghcr.io/appscode/gengo (#199) +- [c1d0d8b](https://github.com/kubevault/installer/commit/c1d0d8b) Stop publishing to docker hub +- [f66a6cd](https://github.com/kubevault/installer/commit/f66a6cd) Use ghcr.io for appscode/golang-dev (#198) +- [e246fef](https://github.com/kubevault/installer/commit/e246fef) Update workflows (Go 1.20, k8s 1.26) (#197) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.15.0](https://github.com/kubevault/operator/releases/tag/v0.15.0) + +- [65c11c92](https://github.com/kubevault/operator/commit/65c11c92) Prepare for release v0.15.0 (#99) +- [2836dc90](https://github.com/kubevault/operator/commit/2836dc90) Configure enableServiceLinks to pod spec (#98) +- [6773611a](https://github.com/kubevault/operator/commit/6773611a) Add Random Suffix with Secret Name (#97) +- [7536eece](https://github.com/kubevault/operator/commit/7536eece) Create SA Token Secret if it does not exist (#96) +- [53843506](https://github.com/kubevault/operator/commit/53843506) Use uid 65534 and test against K8s 1.27.0 (#95) +- [fcc21ef1](https://github.com/kubevault/operator/commit/fcc21ef1) Use ghcr.io for appscode/golang-dev (#94) +- [20b4f38e](https://github.com/kubevault/operator/commit/20b4f38e) Update workflows (Go 1.20, k8s 1.26) (#93) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.15.0](https://github.com/kubevault/unsealer/releases/tag/v0.15.0) + +- [bba14525](https://github.com/kubevault/unsealer/commit/bba14525) Use uid 65534 and test against K8s 1.27.0 (#129) +- [4d994ade](https://github.com/kubevault/unsealer/commit/4d994ade) Use ghcr.io for appscode/golang-dev (#128) +- [7a13d331](https://github.com/kubevault/unsealer/commit/7a13d331) Update workflows (Go 1.20, k8s 1.26) (#127) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2023.9.7.md b/content/docs/v2025.11.21/CHANGELOG-v2023.9.7.md new file mode 100644 index 000000000..ed75980b2 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2023.9.7.md @@ -0,0 +1,92 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2023.9.7 + name: Changelog-v2023.9.7 + parent: welcome + weight: 20230907 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2023.9.7/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2023.9.7/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2023.9.7 (2023-09-07) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.16.0](https://github.com/kubevault/apimachinery/releases/tag/v0.16.0) + +- [349e26c3](https://github.com/kubevault/apimachinery/commit/349e26c3) Update deps (#88) +- [70fe1196](https://github.com/kubevault/apimachinery/commit/70fe1196) Update Object Ref of Role in SAR Sepc (#86) +- [61c7dec1](https://github.com/kubevault/apimachinery/commit/61c7dec1) Show secret name in SecretAccessRequest +- [fb4e4b83](https://github.com/kubevault/apimachinery/commit/fb4e4b83) Update conditions api (#85) +- [d45cf33d](https://github.com/kubevault/apimachinery/commit/d45cf33d) Update license verifier (#84) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.16.0](https://github.com/kubevault/cli/releases/tag/v0.16.0) + +- [d330e716](https://github.com/kubevault/cli/commit/d330e716) Prepare for release v0.16.0 (#180) +- [3a4b07e5](https://github.com/kubevault/cli/commit/3a4b07e5) Update deps (#179) +- [a507b3ee](https://github.com/kubevault/cli/commit/a507b3ee) Update deps +- [0ea76b7e](https://github.com/kubevault/cli/commit/0ea76b7e) Update license verifier (#177) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2023.9.7](https://github.com/kubevault/installer/releases/tag/v2023.9.7) + +- [2794038](https://github.com/kubevault/installer/commit/2794038) Prepare for release v2023.9.7 (#213) +- [3bbace5](https://github.com/kubevault/installer/commit/3bbace5) Update deps (#212) +- [25f1bb8](https://github.com/kubevault/installer/commit/25f1bb8) Enable seccompProfile RuntimeDefault for CI (#211) +- [b3d9ee0](https://github.com/kubevault/installer/commit/b3d9ee0) Update clusterrole to list namespace (#210) +- [e63f017](https://github.com/kubevault/installer/commit/e63f017) Add Vault Version 1.13.3 (#208) +- [22e3460](https://github.com/kubevault/installer/commit/22e3460) Remove seccomp profile for charts (#209) +- [b0cb8d3](https://github.com/kubevault/installer/commit/b0cb8d3) Use helm repo version +- [57aad9b](https://github.com/kubevault/installer/commit/57aad9b) Don't mount license vol when both license and licenseSecretName is empty (#207) +- [9c73417](https://github.com/kubevault/installer/commit/9c73417) Add licenseSecretName values (#206) +- [5cccbed](https://github.com/kubevault/installer/commit/5cccbed) Switch to failurePolicy: Ignore by default for webhooks (#205) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.16.0](https://github.com/kubevault/operator/releases/tag/v0.16.0) + +- [221a32a0](https://github.com/kubevault/operator/commit/221a32a0) Prepare for release v0.16.0 (#108) +- [2809f196](https://github.com/kubevault/operator/commit/2809f196) Update deps (#107) +- [0ca991a4](https://github.com/kubevault/operator/commit/0ca991a4) Fix Vault CR Deletion when Backend DB deleted (#102) +- [addb895b](https://github.com/kubevault/operator/commit/addb895b) Configure seccomp (#106) +- [9e4bb1f6](https://github.com/kubevault/operator/commit/9e4bb1f6) Add cross namespace secret access request (#105) +- [5c549f84](https://github.com/kubevault/operator/commit/5c549f84) Update Conditions API (#104) +- [c3be22cd](https://github.com/kubevault/operator/commit/c3be22cd) Use updated conditions api +- [dc8ac8f8](https://github.com/kubevault/operator/commit/dc8ac8f8) Use restricted pod security label (#103) +- [2de8e148](https://github.com/kubevault/operator/commit/2de8e148) Update license verifier (#101) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.16.0](https://github.com/kubevault/unsealer/releases/tag/v0.16.0) + +- [04800df4](https://github.com/kubevault/unsealer/commit/04800df4) Update deps (#131) +- [f3e89c6f](https://github.com/kubevault/unsealer/commit/f3e89c6f) Update license verifier (#130) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2024.1.26-rc.0.md b/content/docs/v2025.11.21/CHANGELOG-v2024.1.26-rc.0.md new file mode 100644 index 000000000..a7e5f6afc --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2024.1.26-rc.0.md @@ -0,0 +1,75 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2024.1.26-rc.0 + name: Changelog-v2024.1.26-rc.0 + parent: welcome + weight: 20240126 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2024.1.26-rc.0/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2024.1.26-rc.0/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2024.1.26-rc.0 (2024-01-27) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.17.0-rc.0](https://github.com/kubevault/apimachinery/releases/tag/v0.17.0-rc.0) + +- [ca33ed7d](https://github.com/kubevault/apimachinery/commit/ca33ed7d) Add ConfigureOpenAPI helper (#92) +- [9853d93f](https://github.com/kubevault/apimachinery/commit/9853d93f) Update crd fuzzer (#91) +- [6c42ed81](https://github.com/kubevault/apimachinery/commit/6c42ed81) Use k8s 1.29 client libs (#90) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.17.0-rc.0](https://github.com/kubevault/cli/releases/tag/v0.17.0-rc.0) + +- [d3c67d43](https://github.com/kubevault/cli/commit/d3c67d43) Prepare for release v0.17.0-rc.0 (#185) +- [9c748ba6](https://github.com/kubevault/cli/commit/9c748ba6) Use k8s 1.29 client libs (#184) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2024.1.26-rc.0](https://github.com/kubevault/installer/releases/tag/v2024.1.26-rc.0) + +- [299385d](https://github.com/kubevault/installer/commit/299385d) Prepare for release v2024.1.26-rc.0 (#225) +- [9e1c356](https://github.com/kubevault/installer/commit/9e1c356) Use k8s 1.29 client libs (#224) +- [04c5a03](https://github.com/kubevault/installer/commit/04c5a03) Check for image existence (#221) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.17.0-rc.0](https://github.com/kubevault/operator/releases/tag/v0.17.0-rc.0) + +- [9e704219](https://github.com/kubevault/operator/commit/9e704219) Prepare for release v0.17.0-rc.0 (#115) +- [7005dcc7](https://github.com/kubevault/operator/commit/7005dcc7) Use k8s 1.29 client libs (#114) +- [992f326d](https://github.com/kubevault/operator/commit/992f326d) Send hourly audit events (#112) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.17.0-rc.0](https://github.com/kubevault/unsealer/releases/tag/v0.17.0-rc.0) + +- [f46b417e](https://github.com/kubevault/unsealer/commit/f46b417e) Use k8s 1.29 client libs (#133) +- [46940e31](https://github.com/kubevault/unsealer/commit/46940e31) Use k8s 1.29 client libs (#132) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2024.1.28-rc.1.md b/content/docs/v2025.11.21/CHANGELOG-v2024.1.28-rc.1.md new file mode 100644 index 000000000..e979a7c5e --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2024.1.28-rc.1.md @@ -0,0 +1,70 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2024.1.28-rc.1 + name: Changelog-v2024.1.28-rc.1 + parent: welcome + weight: 20240128 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2024.1.28-rc.1/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2024.1.28-rc.1/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2024.1.28-rc.1 (2024-01-28) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.17.0-rc.1](https://github.com/kubevault/apimachinery/releases/tag/v0.17.0-rc.1) + +- [c1e6d898](https://github.com/kubevault/apimachinery/commit/c1e6d898) Update deps + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.17.0-rc.1](https://github.com/kubevault/cli/releases/tag/v0.17.0-rc.1) + +- [18eaa3b5](https://github.com/kubevault/cli/commit/18eaa3b5) Prepare for release v0.17.0-rc.1 (#188) +- [74190f7c](https://github.com/kubevault/cli/commit/74190f7c) Use deps (#187) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2024.1.28-rc.1](https://github.com/kubevault/installer/releases/tag/v2024.1.28-rc.1) + +- [2f29a5e](https://github.com/kubevault/installer/commit/2f29a5e) Prepare for release v2024.1.28-rc.1 (#227) +- [bf6ad16](https://github.com/kubevault/installer/commit/bf6ad16) Use deps (#226) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.17.0-rc.1](https://github.com/kubevault/operator/releases/tag/v0.17.0-rc.1) + +- [94a6564a](https://github.com/kubevault/operator/commit/94a6564a) Prepare for release v0.17.0-rc.1 (#117) +- [fb390cf6](https://github.com/kubevault/operator/commit/fb390cf6) Use deps (#116) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.17.0-rc.1](https://github.com/kubevault/unsealer/releases/tag/v0.17.0-rc.1) + +- [fdbbdc20](https://github.com/kubevault/unsealer/commit/fdbbdc20) Use deps (#134) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2024.1.31.md b/content/docs/v2025.11.21/CHANGELOG-v2024.1.31.md new file mode 100644 index 000000000..828e0412a --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2024.1.31.md @@ -0,0 +1,92 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2024.1.31 + name: Changelog-v2024.1.31 + parent: welcome + weight: 20240131 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2024.1.31/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2024.1.31/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2024.1.31 (2024-01-31) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.17.0](https://github.com/kubevault/apimachinery/releases/tag/v0.17.0) + +- [c1e6d898](https://github.com/kubevault/apimachinery/commit/c1e6d898) Update deps +- [ca33ed7d](https://github.com/kubevault/apimachinery/commit/ca33ed7d) Add ConfigureOpenAPI helper (#92) +- [9853d93f](https://github.com/kubevault/apimachinery/commit/9853d93f) Update crd fuzzer (#91) +- [6c42ed81](https://github.com/kubevault/apimachinery/commit/6c42ed81) Use k8s 1.29 client libs (#90) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.17.0](https://github.com/kubevault/cli/releases/tag/v0.17.0) + +- [16fc1470](https://github.com/kubevault/cli/commit/16fc1470) Prepare for release v0.17.0 (#189) +- [18eaa3b5](https://github.com/kubevault/cli/commit/18eaa3b5) Prepare for release v0.17.0-rc.1 (#188) +- [74190f7c](https://github.com/kubevault/cli/commit/74190f7c) Use deps (#187) +- [d3c67d43](https://github.com/kubevault/cli/commit/d3c67d43) Prepare for release v0.17.0-rc.0 (#185) +- [9c748ba6](https://github.com/kubevault/cli/commit/9c748ba6) Use k8s 1.29 client libs (#184) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2024.1.31](https://github.com/kubevault/installer/releases/tag/v2024.1.31) + +- [fcd744f](https://github.com/kubevault/installer/commit/fcd744f) Prepare for release v2024.1.31 (#228) +- [2f29a5e](https://github.com/kubevault/installer/commit/2f29a5e) Prepare for release v2024.1.28-rc.1 (#227) +- [bf6ad16](https://github.com/kubevault/installer/commit/bf6ad16) Use deps (#226) +- [299385d](https://github.com/kubevault/installer/commit/299385d) Prepare for release v2024.1.26-rc.0 (#225) +- [9e1c356](https://github.com/kubevault/installer/commit/9e1c356) Use k8s 1.29 client libs (#224) +- [04c5a03](https://github.com/kubevault/installer/commit/04c5a03) Check for image existence (#221) +- [1addbed](https://github.com/kubevault/installer/commit/1addbed) Fix registry proxy templates +- [036ffa3](https://github.com/kubevault/installer/commit/036ffa3) Remove k8s 1.19 from CI +- [fbbedff](https://github.com/kubevault/installer/commit/fbbedff) Prepare release: v2023.10.26-rc.0 (#219) +- [4652480](https://github.com/kubevault/installer/commit/4652480) Update catalog registry templates (#216) +- [8770e07](https://github.com/kubevault/installer/commit/8770e07) Update deps + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.17.0](https://github.com/kubevault/operator/releases/tag/v0.17.0) + +- [84268ef1](https://github.com/kubevault/operator/commit/84268ef1) Prepare for release v0.17.0 (#119) +- [3cfeac7b](https://github.com/kubevault/operator/commit/3cfeac7b) Fix Cloud Secret Engines (#118) +- [94a6564a](https://github.com/kubevault/operator/commit/94a6564a) Prepare for release v0.17.0-rc.1 (#117) +- [fb390cf6](https://github.com/kubevault/operator/commit/fb390cf6) Use deps (#116) +- [9e704219](https://github.com/kubevault/operator/commit/9e704219) Prepare for release v0.17.0-rc.0 (#115) +- [7005dcc7](https://github.com/kubevault/operator/commit/7005dcc7) Use k8s 1.29 client libs (#114) +- [992f326d](https://github.com/kubevault/operator/commit/992f326d) Send hourly audit events (#112) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.17.0](https://github.com/kubevault/unsealer/releases/tag/v0.17.0) + +- [fdbbdc20](https://github.com/kubevault/unsealer/commit/fdbbdc20) Use deps (#134) +- [f46b417e](https://github.com/kubevault/unsealer/commit/f46b417e) Use k8s 1.29 client libs (#133) +- [46940e31](https://github.com/kubevault/unsealer/commit/46940e31) Use k8s 1.29 client libs (#132) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2024.3.12.md b/content/docs/v2025.11.21/CHANGELOG-v2024.3.12.md new file mode 100644 index 000000000..e91c409bc --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2024.3.12.md @@ -0,0 +1,70 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2024.3.12 + name: Changelog-v2024.3.12 + parent: welcome + weight: 20240312 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2024.3.12/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2024.3.12/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2024.3.12 (2024-03-12) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.18.0](https://github.com/kubevault/apimachinery/releases/tag/v0.18.0) + +- [f7c76e31](https://github.com/kubevault/apimachinery/commit/f7c76e31) Update deps +- [be8c2cad](https://github.com/kubevault/apimachinery/commit/be8c2cad) Update deps +- [82677dd7](https://github.com/kubevault/apimachinery/commit/82677dd7) Add PKI API (#93) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.18.0](https://github.com/kubevault/cli/releases/tag/v0.18.0) + +- [0a26bfb9](https://github.com/kubevault/cli/commit/0a26bfb9) Prepare for release v0.18.0 (#190) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2024.3.12](https://github.com/kubevault/installer/releases/tag/v2024.3.12) + +- [7963d5d](https://github.com/kubevault/installer/commit/7963d5d) Prepare for release v2024.3.12 (#229) +- [d589023](https://github.com/kubevault/installer/commit/d589023) Fix formatting + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.18.0](https://github.com/kubevault/operator/releases/tag/v0.18.0) + +- [558194fb](https://github.com/kubevault/operator/commit/558194fb) Prepare for release v0.18.0 (#121) +- [67901b68](https://github.com/kubevault/operator/commit/67901b68) Add PKI Engine (#120) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.18.0](https://github.com/kubevault/unsealer/releases/tag/v0.18.0) + + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2024.9.30.md b/content/docs/v2025.11.21/CHANGELOG-v2024.9.30.md new file mode 100644 index 000000000..e0cb800b6 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2024.9.30.md @@ -0,0 +1,85 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2024.9.30 + name: Changelog-v2024.9.30 + parent: welcome + weight: 20240930 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2024.9.30/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2024.9.30/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2024.9.30 (2024-09-27) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.19.0](https://github.com/kubevault/apimachinery/releases/tag/v0.19.0) + +- [223cd4f7](https://github.com/kubevault/apimachinery/commit/223cd4f7) Update deps +- [ae601415](https://github.com/kubevault/apimachinery/commit/ae601415) Use KIND v0.24.0 (#98) +- [f4ffee13](https://github.com/kubevault/apimachinery/commit/f4ffee13) Use Go 1.23 (#97) +- [e0f7e2f7](https://github.com/kubevault/apimachinery/commit/e0f7e2f7) Test against k8s 1.31 (#96) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.19.0](https://github.com/kubevault/cli/releases/tag/v0.19.0) + +- [e9bae879](https://github.com/kubevault/cli/commit/e9bae879) Prepare for release v0.19.0 (#195) +- [2ae41b88](https://github.com/kubevault/cli/commit/2ae41b88) Use Go 1.23 (#194) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2024.9.30](https://github.com/kubevault/installer/releases/tag/v2024.9.30) + +- [e12ee67](https://github.com/kubevault/installer/commit/e12ee67) Prepare for release v2024.9.30 (#238) +- [f2759e3](https://github.com/kubevault/installer/commit/f2759e3) Use seccompProfile RuntimeDefault +- [2b61714](https://github.com/kubevault/installer/commit/2b61714) Update charts +- [581e7fd](https://github.com/kubevault/installer/commit/581e7fd) Add imagelist +- [29358ad](https://github.com/kubevault/installer/commit/29358ad) Revise metrics config user roles +- [d9a1943](https://github.com/kubevault/installer/commit/d9a1943) Remove appcatalog user roles +- [58f6616](https://github.com/kubevault/installer/commit/58f6616) Revise user roles (#237) +- [f44f881](https://github.com/kubevault/installer/commit/f44f881) Use KIND v0.24.0 (#236) +- [1a8a998](https://github.com/kubevault/installer/commit/1a8a998) Use Go 1.23 (#235) +- [02f56cc](https://github.com/kubevault/installer/commit/02f56cc) Test against k8s 1.31 (#234) +- [413f44e](https://github.com/kubevault/installer/commit/413f44e) Fix ca cert key in service monitor +- [ecdc628](https://github.com/kubevault/installer/commit/ecdc628) Remove license checks from webhook server (#232) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.19.0](https://github.com/kubevault/operator/releases/tag/v0.19.0) + +- [9094e13f](https://github.com/kubevault/operator/commit/9094e13ff) Update deps +- [a9ec7f93](https://github.com/kubevault/operator/commit/a9ec7f93e) Use Go 1.23 (#124) +- [5f261077](https://github.com/kubevault/operator/commit/5f2610774) Remove license checks from the webhook server (#123) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.19.0](https://github.com/kubevault/unsealer/releases/tag/v0.19.0) + +- [4ee4d0cd](https://github.com/kubevault/unsealer/commit/4ee4d0cd) Use Go 1.23 (#136) +- [2e0d13e5](https://github.com/kubevault/unsealer/commit/2e0d13e5) Use Go 1.23 (#135) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2025.11.21.md b/content/docs/v2025.11.21/CHANGELOG-v2025.11.21.md new file mode 100644 index 000000000..e418c208b --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2025.11.21.md @@ -0,0 +1,112 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2025.11.21 + name: Changelog-v2025.11.21 + parent: welcome + weight: 20251121 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2025.11.21/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2025.11.21/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2025.11.21 (2025-11-22) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.23.0](https://github.com/kubevault/apimachinery/releases/tag/v0.23.0) + +- [97f01df8](https://github.com/kubevault/apimachinery/commit/97f01df8) Openbao -> OpenBao (#118) +- [d110956b](https://github.com/kubevault/apimachinery/commit/d110956b) Add distribution field (#117) +- [9ed3817b](https://github.com/kubevault/apimachinery/commit/9ed3817b) Fix Raft Backend Health Issue Check (#116) +- [a934f8d9](https://github.com/kubevault/apimachinery/commit/a934f8d9) Test against k8s 1.34 (#115) +- [a1658e08](https://github.com/kubevault/apimachinery/commit/a1658e08) Use Go 1.25 (#114) +- [8692e07b](https://github.com/kubevault/apimachinery/commit/8692e07b) Test against k8s 1.33.2 (#113) +- [db6e0908](https://github.com/kubevault/apimachinery/commit/db6e0908) Test against k8s 1.33.2 (#112) +- [de8dc724](https://github.com/kubevault/apimachinery/commit/de8dc724) Test against k8s 1.33 (#111) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.23.0](https://github.com/kubevault/cli/releases/tag/v0.23.0) + +- [17a9298e](https://github.com/kubevault/cli/commit/17a9298e) Prepare for release v0.23.0 (#211) +- [dbacdc87](https://github.com/kubevault/cli/commit/dbacdc87) Use Go 1.25 (#209) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2025.11.21](https://github.com/kubevault/installer/releases/tag/v2025.11.21) + +- [3379ccf5](https://github.com/kubevault/installer/commit/3379ccf5) Prepare for release v2025.11.21 (#351) +- [a2bcbb7f](https://github.com/kubevault/installer/commit/a2bcbb7f) Add OpenBao Version 2.4.3 (#350) +- [d9df50d9](https://github.com/kubevault/installer/commit/d9df50d9) Update cve report (#347) +- [818ff121](https://github.com/kubevault/installer/commit/818ff121) Update cve report (#346) +- [e88d675b](https://github.com/kubevault/installer/commit/e88d675b) Update cve report (#345) +- [0f9b04a7](https://github.com/kubevault/installer/commit/0f9b04a7) Update cve report (#344) +- [f67e4d69](https://github.com/kubevault/installer/commit/f67e4d69) Update cve report (#343) +- [3b9d98cd](https://github.com/kubevault/installer/commit/3b9d98cd) Update cve report (#342) +- [4013f85f](https://github.com/kubevault/installer/commit/4013f85f) Update cve report (#341) +- [30118eb2](https://github.com/kubevault/installer/commit/30118eb2) Update cve report (#340) +- [673221f6](https://github.com/kubevault/installer/commit/673221f6) Update cve report (#339) +- [6cb11666](https://github.com/kubevault/installer/commit/6cb11666) Update cve report (#338) +- [96a9858f](https://github.com/kubevault/installer/commit/96a9858f) Update cve report (#337) +- [cb1e18d2](https://github.com/kubevault/installer/commit/cb1e18d2) Update cve report (#336) +- [fd591fc1](https://github.com/kubevault/installer/commit/fd591fc1) Update cve report (#335) +- [557914a6](https://github.com/kubevault/installer/commit/557914a6) Test against k8s 1.34 (#334) +- [06c88834](https://github.com/kubevault/installer/commit/06c88834) Update cve report (#333) +- [11d005b8](https://github.com/kubevault/installer/commit/11d005b8) Update cve report (#332) +- [5af36a6f](https://github.com/kubevault/installer/commit/5af36a6f) Update cve report (#331) +- [ba48cd3b](https://github.com/kubevault/installer/commit/ba48cd3b) Update cve report (#330) +- [89472c18](https://github.com/kubevault/installer/commit/89472c18) Use Go 1.25 (#329) +- [635e6b12](https://github.com/kubevault/installer/commit/635e6b12) Test against k8s 1.33.2 (#328) +- [20649874](https://github.com/kubevault/installer/commit/20649874) Test against k8s 1.33.2 (#327) +- [a86ac8f1](https://github.com/kubevault/installer/commit/a86ac8f1) Update cve report (#326) +- [254497cd](https://github.com/kubevault/installer/commit/254497cd) Update cve report (#325) +- [18d95b77](https://github.com/kubevault/installer/commit/18d95b77) Update cve report (#324) +- [8f4e5a9b](https://github.com/kubevault/installer/commit/8f4e5a9b) Update cve report (#323) +- [53176a40](https://github.com/kubevault/installer/commit/53176a40) Update cve report (#322) +- [b8ff6c9b](https://github.com/kubevault/installer/commit/b8ff6c9b) Test against k8s 1.33 (#321) +- [31a3827e](https://github.com/kubevault/installer/commit/31a3827e) Update cve report (#320) +- [4f655e5b](https://github.com/kubevault/installer/commit/4f655e5b) Update cve report (#319) +- [da53639f](https://github.com/kubevault/installer/commit/da53639f) Update cve report (#318) +- [dd39a213](https://github.com/kubevault/installer/commit/dd39a213) Update cve report (#317) +- [236cbe6e](https://github.com/kubevault/installer/commit/236cbe6e) Update cve report (#316) +- [9fb1a7a2](https://github.com/kubevault/installer/commit/9fb1a7a2) Update cve report (#315) +- [87fd2781](https://github.com/kubevault/installer/commit/87fd2781) Update cve report (#314) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.23.0](https://github.com/kubevault/operator/releases/tag/v0.23.0) + +- [93c89049](https://github.com/kubevault/operator/commit/93c890490) Prepare for release v0.23.0 (#142) +- [ba29892f](https://github.com/kubevault/operator/commit/ba29892f3) Raft Backend Health Check Issue Fix (#141) +- [d6bde03c](https://github.com/kubevault/operator/commit/d6bde03c1) Use Go 1.25 (#140) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.23.0](https://github.com/kubevault/unsealer/releases/tag/v0.23.0) + +- [8c906389](https://github.com/kubevault/unsealer/commit/8c906389) Use Go 1.25 (#142) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2025.2.10.md b/content/docs/v2025.11.21/CHANGELOG-v2025.2.10.md new file mode 100644 index 000000000..e823b4fb1 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2025.2.10.md @@ -0,0 +1,126 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2025.2.10 + name: Changelog-v2025.2.10 + parent: welcome + weight: 20250210 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2025.2.10/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2025.2.10/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2025.2.10 (2025-02-07) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.20.0](https://github.com/kubevault/apimachinery/releases/tag/v0.20.0) + +- [1da800c2](https://github.com/kubevault/apimachinery/commit/1da800c2) Disable image caching in setup-qemu action (#103) +- [01a5f6e4](https://github.com/kubevault/apimachinery/commit/01a5f6e4) Fix Makefile +- [0b35b1ab](https://github.com/kubevault/apimachinery/commit/0b35b1ab) make gen fmt +- [8f4ddb6f](https://github.com/kubevault/apimachinery/commit/8f4ddb6f) Update deps +- [38cba2c5](https://github.com/kubevault/apimachinery/commit/38cba2c5) Remove deprecated api calls +- [cd6099c2](https://github.com/kubevault/apimachinery/commit/cd6099c2) Add initContainer config option in VaultServerVersionSpec (#102) +- [41aa54b8](https://github.com/kubevault/apimachinery/commit/41aa54b8) Update github action modules (#101) +- [c8c5b186](https://github.com/kubevault/apimachinery/commit/c8c5b186) Use kind v0.25.0 (#100) +- [b03363cd](https://github.com/kubevault/apimachinery/commit/b03363cd) Use debian:12 base image (#99) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.20.0](https://github.com/kubevault/cli/releases/tag/v0.20.0) + +- [002b17cf](https://github.com/kubevault/cli/commit/002b17cf) Prepare for release v0.20.0 (#199) +- [64bdb08f](https://github.com/kubevault/cli/commit/64bdb08f) Remove vulnerable deps +- [2b5d4b6f](https://github.com/kubevault/cli/commit/2b5d4b6f) Disable image caching in setup-qemu action (#198) +- [6fb84094](https://github.com/kubevault/cli/commit/6fb84094) Prepare for release v0.20.0-rc.0 (#197) +- [59f2343b](https://github.com/kubevault/cli/commit/59f2343b) Update github action modules (#196) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2025.2.10](https://github.com/kubevault/installer/releases/tag/v2025.2.10) + +- [e57d3ef0](https://github.com/kubevault/installer/commit/e57d3ef0) Prepare for release v2025.2.10 (#274) +- [4050f8e5](https://github.com/kubevault/installer/commit/4050f8e5) Update cve report (#273) +- [2e9bd15e](https://github.com/kubevault/installer/commit/2e9bd15e) Disable image caching in setup-qemu action (#272) +- [b4dd8b56](https://github.com/kubevault/installer/commit/b4dd8b56) Prepare for release v2025.2.6-rc.0 (#271) +- [6ea74978](https://github.com/kubevault/installer/commit/6ea74978) Updates for adding `initContainer` in `VaultServerVersion` (#268) +- [fe0a13ff](https://github.com/kubevault/installer/commit/fe0a13ff) Update deps +- [329f0555](https://github.com/kubevault/installer/commit/329f0555) Move user roles to ace-user-roles chart (#269) +- [f88df2d9](https://github.com/kubevault/installer/commit/f88df2d9) Update cve report (#267) +- [ca21ddc8](https://github.com/kubevault/installer/commit/ca21ddc8) Update cve report (#266) +- [0d75cf2b](https://github.com/kubevault/installer/commit/0d75cf2b) Update github action modules (#265) +- [be2d6b21](https://github.com/kubevault/installer/commit/be2d6b21) Update github action modules (#263) +- [6c9fce2b](https://github.com/kubevault/installer/commit/6c9fce2b) Update cve report (#262) +- [b9d25d3c](https://github.com/kubevault/installer/commit/b9d25d3c) Update cve report (#261) +- [698f50e7](https://github.com/kubevault/installer/commit/698f50e7) Update cve report (#260) +- [bcf43d56](https://github.com/kubevault/installer/commit/bcf43d56) Update cve report (#259) +- [aaadf533](https://github.com/kubevault/installer/commit/aaadf533) Check image arch (#258) +- [9d6d3754](https://github.com/kubevault/installer/commit/9d6d3754) Update cve report (#257) +- [9dbe35f9](https://github.com/kubevault/installer/commit/9dbe35f9) Update cve report (#256) +- [cd329618](https://github.com/kubevault/installer/commit/cd329618) Update cve report (#255) +- [d79a7249](https://github.com/kubevault/installer/commit/d79a7249) Use kind v0.25.0 (#254) +- [3a304090](https://github.com/kubevault/installer/commit/3a304090) Update cve report (#253) +- [622a78fe](https://github.com/kubevault/installer/commit/622a78fe) Update cve report (#252) +- [3c5f4197](https://github.com/kubevault/installer/commit/3c5f4197) Update cve report (#251) +- [220f1634](https://github.com/kubevault/installer/commit/220f1634) Update cve report (#250) +- [4f10b560](https://github.com/kubevault/installer/commit/4f10b560) Update cve report (#249) +- [a284ab49](https://github.com/kubevault/installer/commit/a284ab49) Update cve report (#248) +- [7606fb0d](https://github.com/kubevault/installer/commit/7606fb0d) Update cve report (#247) +- [2d1c6d81](https://github.com/kubevault/installer/commit/2d1c6d81) Update cve report (#246) +- [c76eacb0](https://github.com/kubevault/installer/commit/c76eacb0) Update cve report (#245) +- [2ba380d5](https://github.com/kubevault/installer/commit/2ba380d5) Update cve report (#244) +- [c2cb5f45](https://github.com/kubevault/installer/commit/c2cb5f45) Update cve report (#243) +- [ab6bb819](https://github.com/kubevault/installer/commit/ab6bb819) Update cve report (#242) +- [3641fdc6](https://github.com/kubevault/installer/commit/3641fdc6) Update cve report (#241) +- [f0c1ce0e](https://github.com/kubevault/installer/commit/f0c1ce0e) Update deps +- [c71863a2](https://github.com/kubevault/installer/commit/c71863a2) Update cve report 2024-10-24 (#240) +- [28418aa8](https://github.com/kubevault/installer/commit/28418aa8) Generate cve report +- [7461a4b7](https://github.com/kubevault/installer/commit/7461a4b7) Use debian:12 base image (#239) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.20.0](https://github.com/kubevault/operator/releases/tag/v0.20.0) + +- [57c35a6e](https://github.com/kubevault/operator/commit/57c35a6e8) Prepare for release v0.20.0 (#130) +- [197e55a8](https://github.com/kubevault/operator/commit/197e55a88) Update deps +- [f0ba5db1](https://github.com/kubevault/operator/commit/f0ba5db1d) Disable image caching in setup-qemu action (#129) +- [eb1a68e0](https://github.com/kubevault/operator/commit/eb1a68e0d) Prepare for release v0.20.0-rc.0 (#128) +- [59038294](https://github.com/kubevault/operator/commit/590382941) Updates for adding `initContainer` in `VaultServerVersion` (#127) +- [4aba3e3d](https://github.com/kubevault/operator/commit/4aba3e3d0) Update github action modules (#126) +- [3f72441a](https://github.com/kubevault/operator/commit/3f72441a0) Use debian:12 base image (#125) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.20.0](https://github.com/kubevault/unsealer/releases/tag/v0.20.0) + +- [468d2d2f](https://github.com/kubevault/unsealer/commit/468d2d2f) Fix linter +- [a79fe02c](https://github.com/kubevault/unsealer/commit/a79fe02c) Remove vulnerable deps +- [ff793842](https://github.com/kubevault/unsealer/commit/ff793842) Fix CI +- [ed626e15](https://github.com/kubevault/unsealer/commit/ed626e15) Disable image caching in setup-qemu action (#139) +- [45ffd31c](https://github.com/kubevault/unsealer/commit/45ffd31c) Update github action modules (#138) +- [47945d71](https://github.com/kubevault/unsealer/commit/47945d71) Use debian:12 base image (#137) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2025.2.6-rc.0.md b/content/docs/v2025.11.21/CHANGELOG-v2025.2.6-rc.0.md new file mode 100644 index 000000000..d3820ce16 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2025.2.6-rc.0.md @@ -0,0 +1,112 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2025.2.6-rc.0 + name: Changelog-v2025.2.6-rc.0 + parent: welcome + weight: 20250206 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2025.2.6-rc.0/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2025.2.6-rc.0/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2025.2.6-rc.0 (2025-02-06) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.20.0-rc.0](https://github.com/kubevault/apimachinery/releases/tag/v0.20.0-rc.0) + +- [01a5f6e4](https://github.com/kubevault/apimachinery/commit/01a5f6e4) Fix Makefile +- [0b35b1ab](https://github.com/kubevault/apimachinery/commit/0b35b1ab) make gen fmt +- [8f4ddb6f](https://github.com/kubevault/apimachinery/commit/8f4ddb6f) Update deps +- [38cba2c5](https://github.com/kubevault/apimachinery/commit/38cba2c5) Remove deprecated api calls +- [cd6099c2](https://github.com/kubevault/apimachinery/commit/cd6099c2) Add initContainer config option in VaultServerVersionSpec (#102) +- [41aa54b8](https://github.com/kubevault/apimachinery/commit/41aa54b8) Update github action modules (#101) +- [c8c5b186](https://github.com/kubevault/apimachinery/commit/c8c5b186) Use kind v0.25.0 (#100) +- [b03363cd](https://github.com/kubevault/apimachinery/commit/b03363cd) Use debian:12 base image (#99) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.20.0-rc.0](https://github.com/kubevault/cli/releases/tag/v0.20.0-rc.0) + +- [6fb84094](https://github.com/kubevault/cli/commit/6fb84094) Prepare for release v0.20.0-rc.0 (#197) +- [59f2343b](https://github.com/kubevault/cli/commit/59f2343b) Update github action modules (#196) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2025.2.6-rc.0](https://github.com/kubevault/installer/releases/tag/v2025.2.6-rc.0) + +- [b4dd8b56](https://github.com/kubevault/installer/commit/b4dd8b56) Prepare for release v2025.2.6-rc.0 (#271) +- [6ea74978](https://github.com/kubevault/installer/commit/6ea74978) Updates for adding `initContainer` in `VaultServerVersion` (#268) +- [fe0a13ff](https://github.com/kubevault/installer/commit/fe0a13ff) Update deps +- [329f0555](https://github.com/kubevault/installer/commit/329f0555) Move user roles to ace-user-roles chart (#269) +- [f88df2d9](https://github.com/kubevault/installer/commit/f88df2d9) Update cve report (#267) +- [ca21ddc8](https://github.com/kubevault/installer/commit/ca21ddc8) Update cve report (#266) +- [0d75cf2b](https://github.com/kubevault/installer/commit/0d75cf2b) Update github action modules (#265) +- [be2d6b21](https://github.com/kubevault/installer/commit/be2d6b21) Update github action modules (#263) +- [6c9fce2b](https://github.com/kubevault/installer/commit/6c9fce2b) Update cve report (#262) +- [b9d25d3c](https://github.com/kubevault/installer/commit/b9d25d3c) Update cve report (#261) +- [698f50e7](https://github.com/kubevault/installer/commit/698f50e7) Update cve report (#260) +- [bcf43d56](https://github.com/kubevault/installer/commit/bcf43d56) Update cve report (#259) +- [aaadf533](https://github.com/kubevault/installer/commit/aaadf533) Check image arch (#258) +- [9d6d3754](https://github.com/kubevault/installer/commit/9d6d3754) Update cve report (#257) +- [9dbe35f9](https://github.com/kubevault/installer/commit/9dbe35f9) Update cve report (#256) +- [cd329618](https://github.com/kubevault/installer/commit/cd329618) Update cve report (#255) +- [d79a7249](https://github.com/kubevault/installer/commit/d79a7249) Use kind v0.25.0 (#254) +- [3a304090](https://github.com/kubevault/installer/commit/3a304090) Update cve report (#253) +- [622a78fe](https://github.com/kubevault/installer/commit/622a78fe) Update cve report (#252) +- [3c5f4197](https://github.com/kubevault/installer/commit/3c5f4197) Update cve report (#251) +- [220f1634](https://github.com/kubevault/installer/commit/220f1634) Update cve report (#250) +- [4f10b560](https://github.com/kubevault/installer/commit/4f10b560) Update cve report (#249) +- [a284ab49](https://github.com/kubevault/installer/commit/a284ab49) Update cve report (#248) +- [7606fb0d](https://github.com/kubevault/installer/commit/7606fb0d) Update cve report (#247) +- [2d1c6d81](https://github.com/kubevault/installer/commit/2d1c6d81) Update cve report (#246) +- [c76eacb0](https://github.com/kubevault/installer/commit/c76eacb0) Update cve report (#245) +- [2ba380d5](https://github.com/kubevault/installer/commit/2ba380d5) Update cve report (#244) +- [c2cb5f45](https://github.com/kubevault/installer/commit/c2cb5f45) Update cve report (#243) +- [ab6bb819](https://github.com/kubevault/installer/commit/ab6bb819) Update cve report (#242) +- [3641fdc6](https://github.com/kubevault/installer/commit/3641fdc6) Update cve report (#241) +- [f0c1ce0e](https://github.com/kubevault/installer/commit/f0c1ce0e) Update deps +- [c71863a2](https://github.com/kubevault/installer/commit/c71863a2) Update cve report 2024-10-24 (#240) +- [28418aa8](https://github.com/kubevault/installer/commit/28418aa8) Generate cve report +- [7461a4b7](https://github.com/kubevault/installer/commit/7461a4b7) Use debian:12 base image (#239) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.20.0-rc.0](https://github.com/kubevault/operator/releases/tag/v0.20.0-rc.0) + +- [eb1a68e0](https://github.com/kubevault/operator/commit/eb1a68e0d) Prepare for release v0.20.0-rc.0 (#128) +- [59038294](https://github.com/kubevault/operator/commit/590382941) Updates for adding `initContainer` in `VaultServerVersion` (#127) +- [4aba3e3d](https://github.com/kubevault/operator/commit/4aba3e3d0) Update github action modules (#126) +- [3f72441a](https://github.com/kubevault/operator/commit/3f72441a0) Use debian:12 base image (#125) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.20.0-rc.0](https://github.com/kubevault/unsealer/releases/tag/v0.20.0-rc.0) + +- [45ffd31c](https://github.com/kubevault/unsealer/commit/45ffd31c) Update github action modules (#138) +- [47945d71](https://github.com/kubevault/unsealer/commit/47945d71) Use debian:12 base image (#137) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2025.5.26.md b/content/docs/v2025.11.21/CHANGELOG-v2025.5.26.md new file mode 100644 index 000000000..306b9ac7b --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2025.5.26.md @@ -0,0 +1,98 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2025.5.26 + name: Changelog-v2025.5.26 + parent: welcome + weight: 20250526 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2025.5.26/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2025.5.26/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2025.5.26 (2025-05-26) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.21.0](https://github.com/kubevault/apimachinery/releases/tag/v0.21.0) + +- [6afe114b](https://github.com/kubevault/apimachinery/commit/6afe114b) Use k8s 1.32 +- [2c22f1c1](https://github.com/kubevault/apimachinery/commit/2c22f1c1) Test against k8s 1.32 (#109) +- [35becfa4](https://github.com/kubevault/apimachinery/commit/35becfa4) Test against k8s 1.32 (#108) +- [7e13a0f6](https://github.com/kubevault/apimachinery/commit/7e13a0f6) Test against k8s 1.32 (#107) +- [986b66bc](https://github.com/kubevault/apimachinery/commit/986b66bc) Test against k8s 1.32 (#106) +- [c43e3784](https://github.com/kubevault/apimachinery/commit/c43e3784) Test against k8s 1.32 (#105) +- [3aec0d8c](https://github.com/kubevault/apimachinery/commit/3aec0d8c) Use Go 1.24 (#104) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.21.0](https://github.com/kubevault/cli/releases/tag/v0.21.0) + +- [d3c3cf7c](https://github.com/kubevault/cli/commit/d3c3cf7c) Prepare for release v0.21.0 (#207) +- [aa8b8f31](https://github.com/kubevault/cli/commit/aa8b8f31) Use k8s 1.32 client libs (#206) +- [11b40eef](https://github.com/kubevault/cli/commit/11b40eef) Use Go 1.24 (#200) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2025.5.26](https://github.com/kubevault/installer/releases/tag/v2025.5.26) + +- [a9d9a42e](https://github.com/kubevault/installer/commit/a9d9a42e) Prepare for release v2025.5.26 (#309) +- [23a0bde6](https://github.com/kubevault/installer/commit/23a0bde6) Use k8s 1.32 (#308) +- [4970f5d2](https://github.com/kubevault/installer/commit/4970f5d2) Add option to pass priorityclass name to operator pod (#307) +- [e1e3a454](https://github.com/kubevault/installer/commit/e1e3a454) Update cve report (#306) +- [8e529009](https://github.com/kubevault/installer/commit/8e529009) Update cve report (#305) +- [56c75c24](https://github.com/kubevault/installer/commit/56c75c24) Update cve report (#304) +- [2cb5d594](https://github.com/kubevault/installer/commit/2cb5d594) Update cve report (#303) +- [dfe16fd7](https://github.com/kubevault/installer/commit/dfe16fd7) Update cve report (#302) +- [c86852c8](https://github.com/kubevault/installer/commit/c86852c8) Update cve report (#300) +- [8650f0a9](https://github.com/kubevault/installer/commit/8650f0a9) Update cve report (#298) +- [fc69aedf](https://github.com/kubevault/installer/commit/fc69aedf) Update cve report (#297) +- [fdbd2dc1](https://github.com/kubevault/installer/commit/fdbd2dc1) Update cve report (#296) +- [9b45640b](https://github.com/kubevault/installer/commit/9b45640b) Update cve report (#295) +- [fb9ea5a4](https://github.com/kubevault/installer/commit/fb9ea5a4) Update cve report (#294) +- [2d93c3c0](https://github.com/kubevault/installer/commit/2d93c3c0) Update cve report (#293) +- [5c39aab3](https://github.com/kubevault/installer/commit/5c39aab3) Update ace-user-roles +- [86245f71](https://github.com/kubevault/installer/commit/86245f71) Test against k8s 1.32 (#291) +- [e3f0678d](https://github.com/kubevault/installer/commit/e3f0678d) Update cve report (#290) +- [0193897e](https://github.com/kubevault/installer/commit/0193897e) Test against k8s 1.32 (#289) +- [ab39ac08](https://github.com/kubevault/installer/commit/ab39ac08) Update cve report (#288) +- [dbc9f752](https://github.com/kubevault/installer/commit/dbc9f752) Update cve report (#287) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.21.0](https://github.com/kubevault/operator/releases/tag/v0.21.0) + +- [195b7bf3](https://github.com/kubevault/operator/commit/195b7bf30) Prepare for release v0.21.0 (#136) +- [93d5cfa2](https://github.com/kubevault/operator/commit/93d5cfa20) Use k8s 1.32 client libs (#135) +- [094ca87c](https://github.com/kubevault/operator/commit/094ca87c7) make fmt (#134) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.21.0](https://github.com/kubevault/unsealer/releases/tag/v0.21.0) + +- [6a870669](https://github.com/kubevault/unsealer/commit/6a870669) Use k8s 1.32 client libs (#141) +- [7037b619](https://github.com/kubevault/unsealer/commit/7037b619) Use Go 1.24 (#140) + + + + diff --git a/content/docs/v2025.11.21/CHANGELOG-v2025.5.30.md b/content/docs/v2025.11.21/CHANGELOG-v2025.5.30.md new file mode 100644 index 000000000..2566275d9 --- /dev/null +++ b/content/docs/v2025.11.21/CHANGELOG-v2025.5.30.md @@ -0,0 +1,67 @@ +--- +title: Changelog | KubeVault +description: Changelog +menu: + docs_v2025.11.21: + identifier: changelog-kubevault-v2025.5.30 + name: Changelog-v2025.5.30 + parent: welcome + weight: 20250530 +product_name: kubevault +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/changelog-v2025.5.30/ +aliases: +- /docs/v2025.11.21/CHANGELOG-v2025.5.30/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# KubeVault v2025.5.30 (2025-05-29) + + +## [kubevault/apimachinery](https://github.com/kubevault/apimachinery) + +### [v0.22.0](https://github.com/kubevault/apimachinery/releases/tag/v0.22.0) + +- [380e0e7d](https://github.com/kubevault/apimachinery/commit/380e0e7d) Clean up api (#110) + + + +## [kubevault/cli](https://github.com/kubevault/cli) + +### [v0.22.0](https://github.com/kubevault/cli/releases/tag/v0.22.0) + +- [52f7e854](https://github.com/kubevault/cli/commit/52f7e854) Prepare for release v0.22.0 (#208) + + + +## [kubevault/installer](https://github.com/kubevault/installer) + +### [v2025.5.30](https://github.com/kubevault/installer/releases/tag/v2025.5.30) + +- [ba60e56b](https://github.com/kubevault/installer/commit/ba60e56b) Prepare for release v2025.5.30 (#311) + + + +## [kubevault/operator](https://github.com/kubevault/operator) + +### [v0.22.0](https://github.com/kubevault/operator/releases/tag/v0.22.0) + +- [1774969e](https://github.com/kubevault/operator/commit/1774969e8) Prepare for release v0.22.0 (#138) +- [ffbeb738](https://github.com/kubevault/operator/commit/ffbeb738f) Clean up es api (#137) + + + +## [kubevault/unsealer](https://github.com/kubevault/unsealer) + +### [v0.22.0](https://github.com/kubevault/unsealer/releases/tag/v0.22.0) + + + + + diff --git a/content/docs/v2025.11.21/CONTRIBUTING.md b/content/docs/v2025.11.21/CONTRIBUTING.md new file mode 100644 index 000000000..7cc6f3e22 --- /dev/null +++ b/content/docs/v2025.11.21/CONTRIBUTING.md @@ -0,0 +1,60 @@ +--- +title: Contributing | KubeVault +description: Contributing +menu: + docs_v2025.11.21: + identifier: contributing-kubevault + name: Contributing + parent: welcome + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/contributing/ +aliases: +- /docs/v2025.11.21/CONTRIBUTING/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Contribution Guidelines + +Want to hack on KubeVault? + +This document outlines some of the conventions on +development workflow, commit message formatting, contact points and other +resources to make it easier to get your contribution accepted. + +## Certificate of Origin + +By contributing to this project you agree to the Developer Certificate of +Origin (DCO). This document was created by the Linux Kernel community and is a +simple statement that you, as a contributor, have the legal right to make the +contribution. See the [DCO](https://github.com/kubevault/operator/blob/master/DCO) file for details. + +## Getting Help + +To speak with us, please leave a message on [our website](https://appscode.com/contact/). To receive product announcements, follow us on [Twitter](https://twitter.com/KubeVault). + +## Bugs/Feature request + +If you have found a bug with KubeVault or want to request for new features, please [file an issue](https://github.com/kubevault/project/issues/new). + +## Submit PR + + +If you fix a bug or developed a new feature, feel free to submit a PR. In either case, please file a [Github issue](https://github.com/kubevault/project/issues/new) first, so that we can have a discussion on it. This is a rough outline of what a contributor's workflow looks like: +- Create a topic branch from where you want to base your work (usually master). +- Make commits of logical units. +- Push your changes to a topic branch in your fork of the repository. +- Make sure the tests pass, and add any new tests as appropriate. +- Submit a pull request to the original repository. + +Thanks for your contributions! + +## Spread the word + +If you have written blog post or tutorial on KubeVault, please share it with us on [Twitter](https://twitter.com/KubeVault). diff --git a/content/docs/v2025.11.21/README.md b/content/docs/v2025.11.21/README.md new file mode 100644 index 000000000..addc81248 --- /dev/null +++ b/content/docs/v2025.11.21/README.md @@ -0,0 +1,66 @@ +--- +title: Welcome | KubeVault +description: Welcome to KubeVault +menu: + docs_v2025.11.21: + identifier: readme-kubevault + name: Readme + parent: welcome + weight: -1 +menu_name: docs_v2025.11.21 +section_menu_id: welcome +url: /docs/v2025.11.21/welcome/ +aliases: +- /docs/v2025.11.21/ +- /docs/v2025.11.21/README/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +![KubeVault Overview](/docs/v2025.11.21/images/kubevault-overview.svg) + +# KubeVault + +KubeVault by AppsCode is a collection of tools for running HashiCorp [Vault](https://www.vaultproject.io/) on Kubernetes. + +## Operator +You can deploy and manage Vault on Kubernetes clusters using KubeVault operator. From here you can learn all about Vault operator's architecture and how to deploy and use Vault operator. + +- [Concepts](/docs/v2025.11.21/concepts/). Concepts explain the CRDs (CustomResourceDefinition) used by Vault operator. + +- [Setup](/docs/v2025.11.21/setup/). Setup contains instructions for installing + the Vault operator in various cloud providers. + +- [Monitoring](/docs/v2025.11.21/guides/monitoring/overview). Monitoring contains instructions for setup prometheus with Vault server + +- [Guides](/docs/v2025.11.21/guides/). Guides show you how to perform tasks with Vault operator. + +- [Reference](/docs/v2025.11.21/reference/operator). Detailed exhaustive lists of +command-line options, configuration options, API definitions, and procedures. + +## CLI + +[Command line interface](https://github.com/kubevault/cli) for KubeVault. This is intended to be used as a [kubectl plugin](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/). + +- [Reference](/docs/v2025.11.21/reference/cli). Detailed exhaustive lists of command-line options, configuration options, API definitions, and procedures. +- [Installation](/docs/v2025.11.21/setup/install/kubectl_plugin) Install Kubectl Vault Plugin. + +## Unsealer + +[Unsealer](https://github.com/kubevault/unsealer) automates the process of [initializing](https://www.vaultproject.io/docs/commands/operator/init.html) and [unsealing](https://www.vaultproject.io/docs/concepts/seal.html#unsealing) HashiCorp Vault instances running. + +- [Reference](/docs/v2025.11.21/reference/unsealer). Detailed exhaustive lists of command-line options, configuration options, API definitions, and procedures. + +## CSI Driver + +KubeVault works seamlessly with [Secrets Store CSI driver for Kubernetes secrets](https://github.com/kubernetes-sigs/secrets-store-csi-driver). + +- [Reference](https://secrets-store-csi-driver.sigs.k8s.io/) Kubernetes Secrets Store CSI Driver. + + +> We're always looking for help improving our documentation, so please don't hesitate to [file an issue](https://github.com/kubevault/project/issues/new) if you see some problem. Or better yet, submit your own [contributions](/docs/v2025.11.21/CONTRIBUTING) to help +make our docs better. diff --git a/content/docs/v2025.11.21/_index.md b/content/docs/v2025.11.21/_index.md new file mode 100644 index 000000000..9b064a4e4 --- /dev/null +++ b/content/docs/v2025.11.21/_index.md @@ -0,0 +1,17 @@ +--- +title: KubeVault +description: KubeVault +menu: + docs_v2025.11.21: + identifier: welcome + name: Welcome + weight: 10 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/README.md b/content/docs/v2025.11.21/concepts/README.md new file mode 100644 index 000000000..b3aee4c43 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/README.md @@ -0,0 +1,150 @@ +--- +title: KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: concepts-readme + name: Concepts + parent: concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +url: /docs/v2025.11.21/concepts/ +aliases: +- /docs/v2025.11.21/concepts/README/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Concepts + +Concepts help you learn about the different parts of KubeVault and the abstractions it uses. + +- What is KubeVault? + - [Overview](/docs/v2025.11.21/concepts/overview). Provides an introduction to KubeVault operator, including the problems it solves and its use cases. + - [Operator architecture](/docs/v2025.11.21/concepts/architecture). Provides a high-level illustration of the architecture of the KubeVault operator. + + +
+
+ +## AppBinding + +Introduces a way to specify `connection information`, `credential`, and `parameters` that are necessary for communicating with an app or service. + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) + +## Vault Server Version + +Introduces the concept of `VaultServerVersion` to specify the docker images of `HashiCorp Vault`, `Unsealer`, and `Exporter`. + +- [VaultServerVersion](/docs/v2025.11.21/concepts/vault-server-crds/vaultserverversion) + +## Vault Server + +A `VaultServer` is a `Kubernetes CustomResourceDefinition (CRD)` which is used to deploy a `HashiCorp Vault` server on Kubernetes clusters in a Kubernetes native way. Introduces the concept of `VaultServer` for configuring a HashiCorp Vault server in a Kubernetes native way. + +- [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) + +### Vault Unsealer Options +When a `Vault` server is started, it starts in a `sealed` state. In this state, Vault is configured to know where and how to access the physical storage, but doesn't know how to decrypt any of it. + +`Unsealing` is the process of obtaining the plaintext root key necessary to read the decryption key to decrypt the data, allowing access to the Vault. Initializing & Unsealing Vault servers can be a tedious job. +Introduces to various methods of automatically `Initialization` & `Unsealing` Vault Servers. + +- [Overview](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/overview) +- [AWS KMS and SSM](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/aws_kms_ssm) +- [Azure Key Vault](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/azure_key_vault) +- [Google KMS GCS](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/google_kms_gcs) +- [Kubernetes Secret](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/kubernetes_secret) + +### Vault Server Storage +The `storage backend` represents the location for the durable storage of Vault's information. Each backend has pros, cons, advantages, and trade-offs. For example, some backends support `High Availability - HA` while others provide a more robust backup and restoration process. Introduces to various `Storage Backend` options supported by `KubeVault`. + +- [Overview](/docs/v2025.11.21/concepts/vault-server-crds/storage/overview) +- [Azure](/docs/v2025.11.21/concepts/vault-server-crds/storage/azure) +- [DynamoDB](/docs/v2025.11.21/concepts/vault-server-crds/storage/dynamodb) +- [Etcd](/docs/v2025.11.21/concepts/vault-server-crds/storage/etcd) +- [GCS](/docs/v2025.11.21/concepts/vault-server-crds/storage/gcs) +- [In Memory](/docs/v2025.11.21/concepts/vault-server-crds/storage/inmem) +- [MySQL](/docs/v2025.11.21/concepts/vault-server-crds/storage/mysql) +- [PosgreSQL](/docs/v2025.11.21/concepts/vault-server-crds/storage/postgresql) +- [AWS S3](/docs/v2025.11.21/concepts/vault-server-crds/storage/s3) +- [Swift](/docs/v2025.11.21/concepts/vault-server-crds/storage/swift) +- [Consul](/docs/v2025.11.21/concepts/vault-server-crds/storage/consul) +- [Raft](/docs/v2025.11.21/concepts/vault-server-crds/storage/raft) + +### Authentication Methods for Vault Server +`Auth methods` are the components in Vault that perform authentication and are responsible for assigning identity and a set of policies to a user. In all cases, Vault will enforce authentication as part of the request processing. In most cases, Vault will delegate the authentication administration and decision to the relevant configured external auth method (e.g., Amazon Web Services, GitHub, Google Cloud Platform, Kubernetes, Microsoft Azure, Okta, JWT/OIDC). + +Having multiple auth methods enables you to use an auth method that makes the most sense for your use case of `Vault` and your organization. +Introduces to various `Authentication methods` supported by `KubeVault`. + +- [Overview](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/overview) +- [AWS IAM Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/aws-iam) +- [Kubernetes Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/kubernetes) +- [TLS Certificates Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/tls) +- [Token Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/token) +- [Userpass Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/userpass) +- [GCP IAM Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/gcp-iam) +- [Azure Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/azure) +- [JWT/OIDC Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/jwt-oidc) + +
+
+ +## Secret Engine + +`SecretEngine` is a Kubernetes `Custom Resource Definition`(CRD). It provides a way to enable and configure a Vault secret engine. Introduces to `SecretEngine` CRD, fields, & it's various use cases. + +- [Secret Engine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) + +### Secret Engine Roles +In a `Secret Engine`, a `role` describes an identity with a set of `permissions`, `groups`, or `policies` you want to attach a user of the Secret Engine. Introduces to various roles supported by `KubeVault`. + +- [AWSRole](/docs/v2025.11.21/concepts/secret-engine-crds/aws-secret-engine/awsrole) +- [GCPRole](/docs/v2025.11.21/concepts/secret-engine-crds/gcp-secret-engine/gcprole) +- [AzureRole](/docs/v2025.11.21/concepts/secret-engine-crds/azure-secret-engine/azurerole) +- [PKIRole](/docs/v2025.11.21/concepts/secret-engine-crds/pki-secret-engine/pkirole) +- [MongoDBRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mongodb) +- [MySQLRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mysql) +- [PostgresRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/postgresrole) +- [ElasticsearchRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/elasticsearch) +- [MariaDBRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mariadb) +- [RedisRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/redis) + +### Secret Access Request +A `SecretAccessRequest` is a `Kubernetes CustomResourceDefinition (CRD)` which allows a user to request a Vault server for `credentials` in a Kubernetes native way. A `SecretAccessRequest` can be created under various roleRef e.g: `AWSRole`, `GCPRole`, `ElasticsearchRole`, `MongoDBRole`, etc. Introduces to `SecretAccessRequest` CRD, fields & it's various use cases. + +- [SecretAccessRequest](/docs/v2025.11.21/concepts/secret-engine-crds/secret-access-request) + +### Secret Role Binding +A `SecretRoleBinding` is a `Kubernetes CustomResourceDefinition (CRD)` which allows a user to bind a set of `roles` to a set of `users`. Using the `SecretRoleBinding` it’s possible to bind various roles e.g: `AWSRole`, `GCPRole`, `ElasticsearchRole`, `MongoDBRole`, etc. to Kubernetes `ServiceAccounts`. + +- [SecretRoleBinding](/docs/v2025.11.21/concepts/secret-engine-crds/secret-role-binding) + +
+
+ +## Vault Policy + +Everything in the Vault is path-based, and policies are no exception. Policies provide a declarative way to grant or forbid access to certain operations in Vault. Policies are `deny` by default, so an empty policy grants no permission in the system. + +- [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy): is used to create, update or delete Vault policies. +- [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding): is used to create Vault auth roles associated with an authentication type/entity and a set of Vault policies. + +
+
diff --git a/content/docs/v2025.11.21/concepts/_index.md b/content/docs/v2025.11.21/concepts/_index.md new file mode 100755 index 000000000..6a3b66cd9 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/_index.md @@ -0,0 +1,16 @@ +--- +title: Concepts | KubeVault +menu: + docs_v2025.11.21: + identifier: concepts + name: Concepts + weight: 20 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/architecture.md b/content/docs/v2025.11.21/concepts/architecture.md new file mode 100644 index 000000000..c19031ede --- /dev/null +++ b/content/docs/v2025.11.21/concepts/architecture.md @@ -0,0 +1,38 @@ +--- +title: KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: concepts-architecture + name: Architecture + parent: concepts + weight: 20 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + + +![KubeVault operator architecture](/docs/v2025.11.21/images/concepts/architecture.svg) + +# Architecture + +KubeVault operator is composed of the following controllers: + +- A **Vault Server controller** that deploys Vault in Kubernetes clusters. It also injects unsealer and stastd exporter as sidecars to perform unsealing and monitoring respectively. + +- An **Auth controller** that enables auth methods in Vault. + +- A **Policy controller** that manages Vault policies and also binds Vault policies with Kubernetes service accounts. + +- A **Secret Engine controller** that enables and configures Vault [secret engines](https://www.vaultproject.io/docs/secrets/index.html) based on the given configuration. + +- A set of **Role controllers** that configure secret engine roles that are used to generate credentials. + +- A set of **AccessKeyRequest controllers** that generate and issue credentials to the user for various secret engine roles. diff --git a/content/docs/v2025.11.21/concepts/backup-restore/_index.md b/content/docs/v2025.11.21/concepts/backup-restore/_index.md new file mode 100644 index 000000000..8325ed900 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/backup-restore/_index.md @@ -0,0 +1,17 @@ +--- +title: Vault Backup Restore | Concepts | KubeVault +menu: + docs_v2025.11.21: + identifier: backup-restore-concepts + name: Backup & Restore (Stash) + parent: concepts + weight: 30 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/backup-restore/overview.md b/content/docs/v2025.11.21/concepts/backup-restore/overview.md new file mode 100644 index 000000000..4fc6c432c --- /dev/null +++ b/content/docs/v2025.11.21/concepts/backup-restore/overview.md @@ -0,0 +1,87 @@ +--- +title: Vault Backup Restore Overview | KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: overview-backup-restore-concepts + name: Overview + parent: backup-restore-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/README). + +# Backup & Restore Vault Using Stash + +KubeVault uses [Stash](https://stash.run) to backup and restore Vault. Stash by AppsCode is a cloud native data backup and recovery solution for Kubernetes workloads. Stash utilizes [restic](https://github.com/restic/restic) to securely backup stateful applications to any cloud or on-prem storage backends (for example, S3, GCS, Azure Blob storage, Minio, NetApp, Dell EMC etc.). + +## How Backup Works + +The following diagram shows how Stash takes a backup of a Vault cluster. Open the image in a new tab to see the enlarged version. + +
+ Vault Backup Overview +
Fig: Vault Backup Overview
+
+ +The backup process consists of the following steps: + +1. At first, a user creates a secret with access credentials of the backend where the backed up data will be stored. + +2. Then, the user creates a `Repository` crd that specifies the backend information along with the secret that holds the credentials to access the backend. + +3. Then, the user creates a `BackupConfiguration` crd targeting the [AppBinding CRD](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) of the desired Vault cluster. The `BackupConfiguration` object also specifies the `Task` to use to take backup of the Vault cluster. + +4. Stash operator watches for `BackupConfiguration` crd. + +5. Once Stash operator finds a `BackupConfiguration` crd, it creates a CronJob with the schedule specified in `BackupConfiguration` object to trigger backup periodically. + +6. On the next scheduled slot, the CronJob triggers a backup by creating a `BackupSession` crd. + +7. Stash operator also watches for `BackupSession` crd. + +8. When it finds a `BackupSession` object, it resolves the respective `Task` and `Function` and prepares a Job definition to take backup. + +9. Then, it creates the Job to take backup the targeted Vault cluster. + +10. The backup Job reads necessary information to connect with the Vault from the `AppBinding` crd. It also reads backend information and access credentials from `Repository` crd and Storage Secret respectively. + +11. Then, the Job dumps snapshot from the targeted Vault and uploads the output to the backend. Stash stores the dumped files temporarily before uploading into the backend. Hence, you should provide a PVC template using `spec.interimVolumeTemplate` field of `BackupConfiguration` crd to use to store those dumped files temporarily. + +12. Finally, when the backup is completed, the Job sends Prometheus metrics to the Pushgateway running inside Stash operator pod. It also updates the `BackupSession` and `Repository` status to reflect the backup procedure. + +## How Restore Process Works + +The following diagram shows how Stash restores backed up data into a Vault cluster. Open the image in a new tab to see the enlarged version. + +
+ Vault Restore Overview +
Fig: Vault Restore Process
+
+ +The restore process consists of the following steps: + +1. At first, a user creates a `RestoreSession` crd targeting the `AppBinding` of the desired Vault where the backed up data will be restored. It also specifies the `Repository` crd which holds the backend information and the `Task` to use to restore the target. + +2. Stash operator watches for `RestoreSession` object. + +3. Once it finds a `RestoreSession` object, it resolves the respective `Task` and `Function` and prepares a Job definition to restore. + +4. Then, it creates the Job to restore the target. + +5. The Job reads necessary information to connect with the Vault from respective `AppBinding` crd. It also reads backend information and access credentials from `Repository` crd and Storage Secret respectively. + +6. Then, the job downloads the backed up data from the backend and insert into the desired Vault. Stash stores the downloaded files temporarily before inserting into the targeted Vault. Hence, you should provide a PVC template using `spec.interimVolumeTemplate` field of `RestoreSession` crd to use to store those restored files temporarily. + +7. Finally, when the restore process is completed, the Job sends Prometheus metrics to the Pushgateway and update the `RestoreSession` status to reflect restore completion. + +## Next Steps + +- Backup your Vault cluster using Stash following the guide from [here](/docs/v2025.11.21/guides/backup-restore/overview). diff --git a/content/docs/v2025.11.21/concepts/overview.md b/content/docs/v2025.11.21/concepts/overview.md new file mode 100644 index 000000000..48b88936b --- /dev/null +++ b/content/docs/v2025.11.21/concepts/overview.md @@ -0,0 +1,97 @@ +--- +title: What is KubeVault +menu: + docs_v2025.11.21: + identifier: what-is-kubevault-concepts + name: Overview + parent: concepts + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Overview + +## What is KubeVault + +KubeVault operator is a Kubernetes controller for [HashiCorp Vault](https://www.vaultproject.io/). Vault is a tool for secrets management, encryption as a service, and privileged access management. Deploying, maintaining, and managing Vault in Kubernetes could be challenging. KubeVault operator eases these operational tasks so that developers can focus on solving business problems. + +## Why use KubeVault + +KubeVault operator makes it easy to deploy, maintain and manage Vault servers in Kubernetes. It covers automatic initialization and unsealing, and securely stores unseal keys and root tokens in a cloud KMS (Key Management Service) service. It provides the following features: + +- Deploy TLS Secured [Vault Server](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) +- Manage Vault Server [TLS using Cert-manager](/docs/v2025.11.21/concepts/tls-encryption/overview) +- Automate [Initialization & Unseal process of Vault Servers](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/overview) +- Add Durability to Vault's Data using [Storage Backend](/docs/v2025.11.21/concepts/vault-server-crds/storage) +- Enable & Configure [Secret Engines](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) +- Create & Configure [Vault Roles](/docs/v2025.11.21/concepts/secret-engine-crds/gcp-secret-engine/gcprole) +- Manage [Vault Policy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) & [Vault Policy Binding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) +- Manage user privileges using [SecretAccessRequest](/docs/v2025.11.21/concepts/secret-engine-crds/secret-access-request) +- Manage user privileges using [SecretRoleBinding](/docs/v2025.11.21/concepts/secret-engine-crds/secret-role-binding) +- Inject Vault secrets into K8s resources +- Automate tedious operations using [KubeVault CLI](/docs/v2025.11.21/reference/cli) +- Monitor Vault using Prometheus & Grafana Dashboard + +## Core features + +### Deploy TLS Secured Vault Server +A VaultServer is a Kubernetes CustomResourceDefinition (CRD) which is used to deploy a HashiCorp Vault server on Kubernetes clusters in a Kubernetes native way. + +In production, Vault should always use TLS to provide secure communication between clients and the Vault server. You can deploy a TLS secure VaultServer using the KubeVault operator either with the self-signed certificate or with cert-manager to manage VaultServer TLS. + +### Manage Vault Server TLS using Cert-manager +In production, Vault should always use TLS to provide secure communication between clients and the Vault server. KubeVault lets you use cert-manager to manage VaultServer TLS. + +### Automate Initialization & Unseal process of Vault Servers + +When a Vault server is started, it starts in a sealed state. In a sealed state, almost no operation is possible with a Vault server. So, you will need to unseal Vault. + +KubeVault operator provides automatic initialization and unsealing facility. When you deploy or scale up a Vault server, you don't have to worry about unsealing new Vault pods. The KubeVault operator will do it for you. Also, it provides various secure ways to store unseal keys and root token, e.g: Azure Key Vault, AWS KMS SSM, Google KMS GCS or Kubernetes Secret. + +### Enable & Configure Secret Engines +Secrets engines are components which store, generate, or encrypt data. Secrets engines are incredibly flexible, so it is easiest to think about them in terms of their function. Secrets engines are provided with some set of data, they take some action on that data, and they return a result. + +KubeVault lets you enable & configure various Secret Engines e.g: AWS, Azure, Google Cloud KMS, MySQL, MariaDB, Elasticsearch, MongoDB, Postgresql, etc. in a Kubernetes native way. + +### Create & Configure Vault Roles +In a Secret Engine, a role describes an identity with a set of permissions, groups, or policies you want to attach to a user of the Secret Engine. + +KubeVault operator lets you create various roles e.g. AWSRole, AzureRole, GCPRole, MySQLRole, MariaDBRole, ElasticsearchRole, MongoDBRole, PostgresRole, etc. in a SecretEngine. + +### Manage Vault Policy & Vault Policy Binding +Policies in Vault provide a declarative way to grant or forbid access to certain paths and operations in Vault. You can create, delete and update policy in Vault in a Kubernetes native way using KubeVault operator. KubeVault operator also provides a way to bind Vault policy with Kubernetes service accounts using the Vault Policy Binding. ServiceAccounts will have the permissions that are specified in the policy. + +### Manage user privileges using SecretAccessRequest +A SecretAccessRequest is a Kubernetes CustomResourceDefinition (CRD) which allows a user to request a Vault server for credentials in a Kubernetes native way. A SecretAccessRequest can be created under various roles that can be enabled in a SecretEngine e.g: AWSRole, GCPRole, ElasticsearchRole, MongoDBRole, etc. This is a more human friendly way to manage DB privileges. + +KubeVault operator lets you manage your DB user privileges with dynamic secrets rather than hard-coded credentials using SecretAccessRequest. This means that services that need to access a database no longer need to hardcode credentials: they can request them from Vault. Thus granting, revoking and monitoring user privileges is extremely easy with KubeVault. + +### Manage user privileges using SecretRoleBinding +A SecretRoleBinding is a Kubernetes CustomResourceDefinition (CRD) which allows a user to bind a set of roles to a set of users. Using the SecretRoleBinding it’s possible to bind various roles e.g: AWSRole, GCPRole, ElasticsearchRole, MongoDBRole, etc. to Kubernetes ServiceAccounts. This way is more machine friendly and convenient for running your application with specific permissions. + +Injecting Vault Secrets into Kubernetes resources requires specific permissions & using SecretRoleBinding it’s very easy to bind a set of policies to a set of Kubernetes Service Accounts. + +### Inject Vault Secret into Kubernetes resources +Secrets Store CSI Driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a Container Storage Interface (CSI) volume. It allows Kubernetes to mount multiple secrets, keys, and certs stored in enterprise-grade external secrets stores into their pods as a volume. Once the Volume is attached, the data in it is mounted into the container’s file system. + +KubeVault operator works seamlessly with Secrets Store CSI Driver. This is one of the recommended ways to mount Vault Secrets into Kubernetes resources along with Vault Agent Sidecar Injector. + +Secrets Store CSI Driver requires a SecretProviderClass which is a namespaced resource that is used to provide driver configurations and provider-specific parameters to the CSI driver. Writing these SecretProviderClass can be a tedious job, but KubeVault CLI lets you generate SecretProviderClass using simple CLI commands. + +### Automate tedious operations using KubeVault CLI +KubeVault CLI is an integral part of the KubeVault operator. It makes various tasks simple while working with the operator e.g. Approve/Deny/Revoke SecretAccessRequest, Generate SecretProviderClass, Get, Set, List, Sync Vault Unseal Keys and Vault Root Token, etc. + +### Monitor Vault using Prometheus & Grafana Dashboard +You can monitor Vault servers using the Vault dashboard. + + +KubeVault operator has native support for monitoring via [Prometheus](https://prometheus.io/). You can use builtin [Prometheus](https://github.com/prometheus/prometheus) scraper or [Prometheus Operator](https://github.com/coreos/prometheus-operator) to monitor KubeVault operator. diff --git a/content/docs/v2025.11.21/concepts/policy-crds/_index.md b/content/docs/v2025.11.21/concepts/policy-crds/_index.md new file mode 100755 index 000000000..c2e9b4578 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/policy-crds/_index.md @@ -0,0 +1,17 @@ +--- +title: Concepts | Vault Policy +menu: + docs_v2025.11.21: + identifier: policy-crds-concepts + name: Vault Policy + parent: concepts + weight: 50 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/policy-crds/vaultpolicy.md b/content/docs/v2025.11.21/concepts/policy-crds/vaultpolicy.md new file mode 100644 index 000000000..d1d470724 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/policy-crds/vaultpolicy.md @@ -0,0 +1,125 @@ +--- +title: VaultPolicy | KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: vaultpolicy-policy-crds + name: VaultPolicy + parent: policy-crds-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# VaultPolicy + +## What is VaultPolicy + +A `VaultPolicy` is a Kubernetes `CustomResourceDefinition` (CRD) which represents Vault server [policies](https://www.vaultproject.io/docs/concepts/policies.html) in a Kubernetes native way. + +When a `VaultPolicy` is created, the KubeVault operator will create a policy in the associated Vault server according to specification. If the `VaultPolicy` CRD is deleted, the respective policy will also be deleted from the Vault server. + +![Vault Policy CRD](/docs/v2025.11.21/images/concepts/vault_policy.svg) + +## VaultPolicy CRD Specification + +Like any official Kubernetes resource, a `VaultPolicy` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `VaultPolicy` object is shown below: + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: secret-admin + namespace: default +spec: + vaultRef: + name: vault + policyDocument: | + path "secret/*" { + capabilities = ["create", "read", "update", "delete", "list"] + } +status: + observedGeneration: 1 + phase: Success +``` + +Here, we are going to describe the various sections of the `VaultPolicy` crd. + +### VaultPolicy Spec + +VaultPolicy `spec` contains policy and vault information necessary to create a [Vault policy](https://www.vaultproject.io/docs/concepts/policies.html). `VaultPolicy` CRD has the following fields in the `.spec` section. + +#### spec.vaultRef + +`spec.vaultRef` is a `required` field that specifies the name of an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) reference which is used to connect with a Vault server. AppBinding must be on the same namespace with VaultPolicy object. + +```yaml +spec: + vaultRef: + name: vault-app +``` + +#### spec.vaultPolicyName + +To resolve the naming conflict, KubeVault operator will generate policy names in Vault server in this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. `spec.vaultPolicyName` is an `optional` field. If set, it will overwrite the generated policy name in Vault server. + +```yaml +spec: + vaultPolicyName: my-custom-policy +``` + +#### spec.policyDocument + +`spec.policyDocument` is an `optional` field that specifies the vault policy in `hcl` format. Both `spec.policyDocument` and `spec.policy` cannot be empty at once. + +```yaml +spec: + policyDocument: | + path "secret/*" { + capabilities = ["create", "read", "update", "delete", "list"] + } + path "abc/*" { + capabilities = ["read"] + } +``` + +#### spec.policy + +Vault uses [HCL](https://github.com/hashicorp/hcl) as its configuration language. HCL is also fully JSON compatible. That is, JSON can be used as a completely valid input to a system expecting HCL. This helps to make systems interoperable with other systems. + +`spec.policy` is an `optional` field that accepts the vault policy in `YAML` format. This can be more convenient since Kubernetes uses YAML as its native configuration language. + +```yaml +spec: + policy: + path: + secret/*: + capabilities: + - create + - read + - update + - delete + - list + abc/*: + capabilities: + - read +``` + +### VaultPolicy Status + +VaultPolicy `status` shows the status of a Vault Policy. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, which is updated on mutation by the API Server. + +- `phase`: Indicates whether the policy successfully applied to Vault or failed. + +- `conditions` : Represents the latest available observations of a VaultPolicy's current state. diff --git a/content/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding.md b/content/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding.md new file mode 100644 index 000000000..1f9e2f26c --- /dev/null +++ b/content/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding.md @@ -0,0 +1,178 @@ +--- +title: VaultPolicyBinding | KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: vaultpolicybinding-policy-crds + name: VaultPolicyBinding + parent: policy-crds-concepts + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# VaultPolicyBinding + +## What is VaultPolicyBinding + +A `VaultPolicyBinding` is a Kubernetes `CustomResourceDefinition` (CRD) which binds Vault server [policies](https://www.vaultproject.io/docs/concepts/policies.html) to an auth method role in a Kubernetes native way. + +When a `VaultPolicyBinding` is created, the KubeVault operator will create an auth role according to CRD (CustomResourceDefinition) specification. +If the user deletes the VaultPolicyBinding CRD, then the respective role will also be deleted from Vault. + +![VaultPolicyBinding CRD](/docs/v2025.11.21/images/concepts/vault_policy_binding.svg) + +Auth method roles are associated with an authentication type/entity and a set of Vault policies. Currently supported auth methods for VaultPolicyBinding: + +- [Kubernetes Auth Method](https://www.vaultproject.io/docs/auth/kubernetes.html): The Kubernetes auth method can be used to authenticate with Vault using a Kubernetes Service Account Token. This method of authentication makes it easy to introduce a Vault token into a Kubernetes Pod. + +## VaultPolicyBinding CRD Specification + +Like any official Kubernetes resource, a `VaultPolicyBinding` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `VaultPolicyBinding` object is shown below: + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: admin-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: secret-admin + subjectRef: + kubernetes: + serviceAccountNames: + - "demo sa" + serviceAccountNamespaces: + - "demo" + ttl: "1000" + maxTTL: "2000" + period: "1000" +status: + observedGeneration: 1 + phase: Success +``` + +Here, we are going to describe the various sections of the `VaultPolicyBinding` crd. + +### VaultPolicyBinding Spec + +VaultPolicyBinding `spec` contains information that is necessary for creating an auth role. + +```yaml +spec: + vaultRef: + name: + vaultRoleName: + policies: + - name: + ref: + subjectRef: + kubernetes: + path: + serviceAccountNames: + - "sa1" + - "sa2" + serviceAccountNamespaces: + - "ns1" + ttl: + maxTTL: + period: +``` + +VaultPolicyBinding spec has the following fields: + +#### spec.vaultRef + +`spec.vaultRef` is a `required` field that specifies the name of an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains information to communicate with a Vault server. The AppBinding object must be in the same namespace with VaultPolicyBinding object. + +```yaml +spec: + vaultRef: + name: vault-app +``` + +#### spec.vaultRoleName + +To avoid naming conflict, KubeVault operator will generate role names in Vault server in this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. `spec.vaultRoleName` is an `optional` field. If set, it will be used instead of the auto-generated role name. + +```yaml +spec: + vaultRoleName: my-custom-role +``` + +#### spec.policies + +`spec.policies` is a `required` field that specifies a list of vault policy references. Each item of the list +can be **either** a vault policy name **or** VaultPolicy CRD name. + +- `name`: Specifies the [vault policy](https://www.vaultproject.io/docs/concepts/policies.html) name. + This name should be returned by `vault read sys/policy` command. + +- `ref`: Specifies the name of [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) crd object. The KubeVault operator will get the vault policy name + from the crd object. + +```yaml +spec: + policies: + - name: policy1 + - ref: policy2 +``` + +#### spec.subjectRef + +`spec.subjectRef` is a `required` field that specifies the reference of vault users who will be granted +token with mentioned policies. + +- `kubernetes`: Refers to vault users who will be authenticated via the Kubernetes auth method. + + - `path` : `Optional`. Specifies the path where the Kubernetes auth is enabled. The default value is `kubernetes`. + + - `serviceAccountNames` : `Required`. Specifies the list of service account names. + They will have access to use this role. If set to `"*"` all names are allowed, + both this and serviceAccountNamespaces **cannot** be `"*"`. + + - `serviceAccountNamespaces` : `Required`. Specifies a list of namespaces allowed to access this role. This value set to "*" means + all namespaces are allowed. + + - `ttl` : `Optional`. Specifies the TTL period of the token issued using this role in seconds. Default value "0". + + - `maxTTL` : `Optional`. Specifies the maximum allowed lifetime of tokens issued in seconds using this role. + + - `period` : `Optional`. If set indicates that the token generated using this role should never expire. The token should be renewed within the + duration specified by this value. At each renewal, the token's TTL will be set to the value of this parameter. + +```yaml +spec: + subjectRef: + kubernetes: + serviceAccountNames: + - "sa1" + - "sa2" + serviceAccountNamespaces: + - "demo" + ttl: "1000" + maxTTL: "2000" + period: "1000" +``` + +### VaultPolicyBinding Status + +`status` shows the status of a VaultPolicyBinding. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, which is updated on mutation by the API Server. + +- `phase`: Indicates whether the role successfully created in the Vault or not. + +- `conditions` : Represents the latest available observations of a VaultPolicyBinding's current state. diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/_index.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/_index.md new file mode 100755 index 000000000..f0244281d --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/_index.md @@ -0,0 +1,17 @@ +--- +title: Secret Engine CRD | KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: secret-engine-crds-concepts + name: Secret Engines + parent: concepts + weight: 40 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/aws-secret-engine/_index.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/aws-secret-engine/_index.md new file mode 100755 index 000000000..60ada2325 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/aws-secret-engine/_index.md @@ -0,0 +1,17 @@ +--- +title: Concepts | AWS Secret Engine +menu: + docs_v2025.11.21: + identifier: aws-crds-concepts + name: AWS + parent: secret-engine-crds-concepts + weight: 20 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/aws-secret-engine/awsrole.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/aws-secret-engine/awsrole.md new file mode 100644 index 000000000..111b2863b --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/aws-secret-engine/awsrole.md @@ -0,0 +1,192 @@ +--- +title: AwsRole | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: awsrole-secret-engine-crds + name: AwsRole + parent: aws-crds-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# AWSRole + +## What is AWSRole + +An `AWSRole` is a Kubernetes `CustomResourceDefinition` (CRD) which allows a user to create AWS secret engine role in a Kubernetes native way. + +When an `AWSRole` is created, the KubeVault operator [configures](https://www.vaultproject.io/docs/secrets/aws/index.html#setup) a Vault role that maps to a set of permissions in AWS as well as an AWS credential type. When users generate credentials, they are generated against this role. If the user deletes the `AWSRole` CRD, +then the respective role will also be deleted from Vault. + +![AWSRole CRD](/docs/v2025.11.21/images/concepts/aws_role.svg) + +## AWSRole CRD Specification + +Like any official Kubernetes resource, a `AWSRole` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `AWSRole` object is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: AWSRole +metadata: + name: aws-cred + namespace: demo +spec: + secretEngineRef: + name: aws-secret-engine + credentialType: iam_user + policyDocument: | + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "ec2:*", + "Resource": "*" + } + ] + } +status: + observedGeneration: 1 + phase: Success +``` + +> Note: To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}` + +Here, we are going to describe the various sections of the `AWSRole` crd. + +### AWSRole Spec + +AWSRole `spec` contains root IAM credentials configuration and role information. + +```yaml +spec: + secretEngineRef: + name: + path: + credentialType: + roleARNs: + - "ARN1" + - "ARN2" + policyARNs: + - "ARN1" + - "ARN2" + policyDocument: + policy: + defaultSTSTTL: + maxSTSTTL: +``` + +`AWSRole` spec has the following fields: + +#### spec.secretEngineRef + +`spec.secretEngineRef` is a `required` field that specifies the name of a `SecretEngine`. + +```yaml +spec: + secretEngineRef: + name: aws-secret-engine +``` + +#### spec.credentialType + +`spec.credentialType` is a `required` field that specifies the type of credential to be used when retrieving credentials from the role. Supported types: `iam_user`, `assumed_role` and `federation_token`. + +```yaml +spec: + credentialType: iam_user +``` + +#### spec.roleARNs + +`spec.roleARNs` is an `optional` field that specifies the list of ARNs of the AWS roles this Vault role is allowed to assume. + +```yaml +spec: + roleARNs: + - arn:aws:iam::452618475015:role/hello.world +``` + +#### spec.policyARNs + +`spec.policyARNs` is an `optional` field that specifies the list of ARNs of the AWS managed policies to be attached to IAM users when they are requested. + +```yaml +spec: + policyARNs: + - arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess +``` + +#### spec.policyDocument + +`spec.policyDocument` is an `optional` field that specifies the IAM policy document for the role. + +```yaml +spec: + policyDocument: | + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "ec2:*", + "Resource": "*" + } + ] + } +``` + +#### spec.policy + +`spec.policy` is an `optional` field that specifies the IAM policy in JSON format. + This field is for backward compatibility only. + +```yaml +spec: + policy: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: ec2:* + Resource: "*" +``` + +#### spec.defaultSTSTTL + +`spec.defaultSTSTTL` is an `optional` field that specifies the default TTL for STS credentials. When a TTL is not specified when STS credentials are requested, and a default TTL is specified +on the role, then this default TTL will be used. This is valid only when `spec.credentialType` is one of `assumed_role` or `federation_token`. + +```yaml +spec: + defaultSTSTTL: "1h" +``` + +#### spec.maxSTSTTL + +`spec.maxSTSTTL` is an `optional` field that specifies the max allowed TTL for STS credentials. This is valid only when `spec.credentialType` is one of `assumed_role` or `federation_token`. + +```yaml +spec: + maxSTSTTL: "1h" +``` + +### AWSRole Status + +`status` shows the status of the AWSRole. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, which is updated on mutation by the API Server. + +- `phase`: Indicates whether the role successfully applied to Vault or not. + +- `conditions` : Represent observations of an AWSRole. diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/azure-secret-engine/_index.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/azure-secret-engine/_index.md new file mode 100755 index 000000000..4dd58efae --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/azure-secret-engine/_index.md @@ -0,0 +1,17 @@ +--- +title: Concepts | Azure Secret Engine +menu: + docs_v2025.11.21: + identifier: azure-crds-concepts + name: Azure + parent: secret-engine-crds-concepts + weight: 30 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/azure-secret-engine/azurerole.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/azure-secret-engine/azurerole.md new file mode 100644 index 000000000..64195002c --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/azure-secret-engine/azurerole.md @@ -0,0 +1,140 @@ +--- +title: AzureRole | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: azurerole-secret-engine-crds + name: AzureRole + parent: azure-crds-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# AzureRole + +## What is AzureRole + +An `AzureRole` is a Kubernetes `CustomResourceDefinition` (CRD) which allows a user to create an Azure secret engine role in a Kubernetes native way. + +When an `AzureRole` is created, the KubeVault operator [configures](https://www.vaultproject.io/docs/secrets/azure/index.html#setup) a Vault role. +A role may be set up with either an existing service principal or a set of Azure roles that will be assigned to a dynamically created service principal. +If the user deletes the `AzureRole` CRD, then the respective role will also be deleted from Vault. + +![AzureRole CRD](/docs/v2025.11.21/images/concepts/azure_role.svg) + +## AzureRole CRD Specification + +Like any official Kubernetes resource, a `AzureRole` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `AzureRole` object is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: AzureRole +metadata: + name: azure-role + namespace: demo +spec: + secretEngineRef: + name: azure-secret-engine + azureRoles: `[ + { + "role_name": "Contributor", + "scope": "/subscriptions//resourceGroups/Website" + } + ]` + applicationObjectID: c1cb042d-96d7-423a-8dba-243c2e5010d3 +status: + observedGeneration: 1 + phase: Success +``` + +> Note: To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}` + +Here, we are going to describe the various sections of the `AzureRole` crd. + +### AzureRole Spec + +AzureRole `spec` contains either new service principal configuration or existing service principal name required for configuring a role. + +```yaml +spec: + secretEngineRef: + name: + path: + applicationObjectID: + azureRoles: + ttl: + maxTTL: +``` + +`AzureRole` spec has the following fields: + +#### spec.secretEngineRef + +`spec.secretEngineRef` is a `required` field that specifies the name of a `SecretEngine`. + +```yaml +spec: + secretEngineRef: + name: azure-secret-engine +``` + +#### spec.azureRoles + +`spec.azureRoles` is an `optional` field that specifies a list of Azure roles to be assigned to the generated service principal. The array must be in JSON format, properly escaped as a string. + +```yaml +spec: + azureRoles: `[ + { + "role_name": "Contributor", + "scope": "/subscriptions//resourceGroups/Website" + } + ]` +``` + +#### spec.applicationObjectID + +`spec.applicationObjectID` is an `optional` field that specifies the Application Object ID for an existing service principal that will be used instead of creating dynamic service principals. If present, azure_roles will be ignored. See [roles docs](https://www.vaultproject.io/docs/secrets/azure/index.html#roles) for details on role definition. + +```yaml +spec: + applicationObjectID: c1cb042d-96d7-423a-8dba-243c2e5010d3 +``` + +#### spec.ttl + +Specifies the default TTL for service principals generated using this role. Accepts time suffixed strings ("1h") or an integer number of seconds. Defaults to the system/engine default TTL time. + +```yaml +spec: + ttl: 1h +``` + +#### spec.maxTTL + +Specifies the maximum TTL for service principals generated using this role. Accepts time suffixed strings ("1h") or an integer number of seconds. Defaults to the system/engine max TTL time. + +```yaml +spec: + maxTTL: 1h +``` + +### AzureRole Status + +`status` shows the status of the AzureRole. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, which is updated on mutation by the API Server. + +- `phase`: Indicates whether the role successfully applied to Vault or not. + +- `conditions` : Represent observations of an AzureRole. diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/_index.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/_index.md new file mode 100755 index 000000000..8a58fae8f --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/_index.md @@ -0,0 +1,17 @@ +--- +title: Concepts | Database Secret Engine +menu: + docs_v2025.11.21: + identifier: database-crds-concepts + name: Database + parent: secret-engine-crds-concepts + weight: 60 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/elasticsearch.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/elasticsearch.md new file mode 100644 index 000000000..cec58af39 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/elasticsearch.md @@ -0,0 +1,129 @@ +--- +title: ElasticsearchRole | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: elasticsearch-database-crds + name: ElasticsearchRole + parent: database-crds-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# ElasticsearchRole + +## What is ElasticsearchRole + +A `ElasticsearchRole` is a Kubernetes `CustomResourceDefinition` (CRD) which allows a user to create an Elasticsearch database secret engine role in a Kubernetes native way. + +When a `ElasticsearchRole` is created, the KubeVault operator creates a Vault [role](https://www.vaultproject.io/api/secret/databases/index.html#create-role) according to the specification. +If the user deletes the `ElasticsearchRole` CRD, then the respective role will also be deleted from Vault. + +![ElasticsearchRole CRD](/docs/v2025.11.21/images/concepts/elasticsearch_role.svg) + +## ElasticsearchRole CRD Specification + +Like any official Kubernetes resource, a `ElasticsearchRole` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `ElasticsearchRole` object is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: ElasticsearchRole +metadata: + name: es-role + namespace: demo +spec: + secretEngineRef: + name: es-secret-engine + creationStatements: + - "statement-0" + - "statement-1" +status: + observedGeneration: 1 + phase: Success +``` + +> Note: To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}` + +Here, we are going to describe the various sections of the `ElasticsearchRole` crd. + +### ElasticsearchRole Spec + +ElasticsearchRole `spec` contains information that necessary for creating a database role. + +```yaml +spec: + secretEngineRef: + name: + path: + defaultTTL: + maxTTL: + creationStatements: + - "statement-0" + - "statement-1" + revocationStatements: + - "statement-0" +``` + +ElasticsearchRole spec has the following fields: + +#### spec.secretEngineRef + +`spec.secretEngineRef` is a `required` field that specifies the name of a `SecretEngine`. + +```yaml +spec: + secretEngineRef: + name: vault-app +``` + +#### spec.creationStatements + +`spec.creationStatements` is a `required` field that specifies a list of database statements executed to create and configure a user. +See in [here](https://www.vaultproject.io/api/secret/databases/elasticdb.html#creation_statements) for Vault documentation. + +```yaml +spec: + creationStatements: + - "{"elasticsearch_roles": ["superuser"]}" +``` + +#### spec.defaultTTL + +`spec.defaultTTL` is an `optional` field that specifies the TTL for the leases associated with this role. Accepts time suffixed strings ("1h") or an integer number of seconds. +Defaults to system/engine default TTL time. + +```yaml +spec: + defaultTTL: "1h" +``` + +#### spec.maxTTL + +`spec.maxTTL` is an `optional` field that specifies the maximum TTL for the leases associated with this role. Accepts time suffixed strings ("1h") or an integer number of seconds. +Defaults to system/engine default TTL time. + +```yaml +spec: + maxTTL: "1h" +``` + +### ElasticsearchRole Status + +`status` shows the status of the ElasticsearchRole. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, + which is updated on mutation by the API Server. + +- `phase`: Indicates whether the role successfully applied to Vault or not. + +- `conditions` : Represent observations of a ElasticsearchRole. diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mariadb.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mariadb.md new file mode 100644 index 000000000..d4117083b --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mariadb.md @@ -0,0 +1,135 @@ +--- +title: MariaDBRole | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: mariadb-database-crds + name: MariaDBRole + parent: database-crds-concepts + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# MariaDBRole + +## What is MariaDBRole + +A `MariaDBRole` is a Kubernetes `CustomResourceDefinition` (CRD) which allows a user to create a database secret engine role in a Kubernetes native way. + +When a `MariaDBRole` is created, the KubeVault operator creates a +[role](https://www.vaultproject.io/api/secret/databases/index.html#create-role) according to the specification. +If the user deletes the `MariaDBRole` CRD, then the respective role will also be deleted from Vault. + +![MariaDBRole CRD](/docs/v2025.11.21/images/concepts/mariadb_role.svg) + +## MariaDBRole CRD Specification + +Like any official Kubernetes resource, a `MariaDBRole` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `MariaDBRole` object is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: MariaDBRole +metadata: + name: mariadb-role + namespace: demo +spec: + secretEngineRef: + name: mariadb-secret-engine + creationStatements: + - "CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';" + - "GRANT SELECT ON *.* TO '{{name}}'@'%';" +status: + observedGeneration: 1 + phase: Success +``` + +> Note: To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}` + +Here, we are going to describe the various sections of the `MariaDBRole` crd. + +### MariaDBRole Spec + +MariaDBRole `spec` contains information that necessary for creating a database role. + +```yaml +spec: + secretEngineRef: + name: + path: + defaultTTL: + maxTTL: + creationStatements: + - "statement-0" + - "statement-1" + revocationStatements: + - "statement-0" +``` + +MariaDBRole spec has the following fields: + +#### spec.secretEngineRef + +`spec.secretEngineRef` is a `required` field that specifies the name of a `SecretEngine`. + +```yaml +spec: + secretEngineRef: + name: mariadb-secret-engine +``` + +#### spec.creationStatements + +`spec.creationStatements` is a `required` field that specifies a list of database statements executed to create and configure a user. +The `{{name}}` and `{{password}}` values will be substituted by Vault. + +```yaml +spec: + creationStatements: + - "CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';" + - "GRANT SELECT ON *.* TO '{{name}}'@'%';" +``` + +#### spec.defaultTTL + +`spec.defaultTTL` is an `optional` field that specifies the TTL for the leases associated with this role. +Accepts time suffixed strings ("1h") or an integer number of seconds. Defaults to system/engine default TTL time. + +```yaml +spec: + defaultTTL: "1h" +``` + +#### spec.maxTTL + +`spec.maxTTL` is an `optional` field that specifies the maximum TTL for the leases associated with this role. +Accepts time suffixed strings ("1h") or an integer number of seconds. Defaults to system/engine default TTL time. + +```yaml +spec: + maxTTL: "1h" +``` + +#### spec.revocationStatements + +`spec.revocationStatements` is an `optional` field that specifies a list of database statements to be executed to revoke a user. The `{{name}}` value will be substituted. If not provided defaults to a generic drop user statement. + +### MariaDBRole Status + +`status` shows the status of the MariaDBRole. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, + which is updated on mutation by the API Server. + +- `phase`: Indicates whether the role successfully applied to Vault or not. + +- `conditions` : Represent observations of a MariaDBRole. diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mongodb.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mongodb.md new file mode 100644 index 000000000..b07524b3c --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mongodb.md @@ -0,0 +1,135 @@ +--- +title: MongoDBRole | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: mongodb-database-crds + name: MongoDBRole + parent: database-crds-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# MongoDBRole + +## What is MongoDBRole + +A `MongoDBRole` is a Kubernetes `CustomResourceDefinition` (CRD) which allows a user to create a MongoDB database secret engine role in a Kubernetes native way. + +When a `MongoDBRole` is created, the KubeVault operator creates a Vault [role](https://www.vaultproject.io/api/secret/databases/index.html#create-role) according to the specification. +If the user deletes the `MongoDBRole` CRD, then the respective role will also be deleted from Vault. + +![MongoDBRole CRD](/docs/v2025.11.21/images/concepts/mongodb_role.svg) + +## MongoDBRole CRD Specification + +Like any official Kubernetes resource, a `MongoDBRole` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `MongoDBRole` object is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: MongoDBRole +metadata: + name: mdb-role + namespace: demo +spec: + secretEngineRef: + name: es-secret-engine + creationStatements: + - "statement-0" + - "statement-1" +status: + observedGeneration: 1 + phase: Success +``` + +> Note: To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}` + +Here, we are going to describe the various sections of the `MongoDBRole` crd. + +### MongoDBRole Spec + +MongoDBRole `spec` contains information that necessary for creating a database role. + +```yaml +spec: + secretEngineRef: + name: + path: + defaultTTL: + maxTTL: + creationStatements: + - "statement-0" + - "statement-1" + revocationStatements: + - "statement-0" +``` + +MongoDBRole spec has the following fields: + +#### spec.secretEngineRef + +`spec.secretEngineRef` is a `required` field that specifies the name of a `SecretEngine`. + +```yaml +spec: + secretEngineRef: + name: es-secret-engine +``` + +#### spec.creationStatements + +`spec.creationStatements` is a `required` field that specifies a list of database statements executed to create and configure a user. +See in [here](https://www.vaultproject.io/api/secret/databases/mongodb.html#creation_statements) for Vault documentation. + +```yaml +spec: + creationStatements: + - "{ \"db\": \"admin\", \"roles\": [{ \"role\": \"readWrite\" }, {\"role\": \"read\", \"db\": \"foo\"}] }" +``` + +#### spec.defaultTTL + +`spec.defaultTTL` is an `optional` field that specifies the TTL for the leases associated with this role. Accepts time suffixed strings ("1h") or an integer number of seconds. + Defaults to system/engine default TTL time. + +```yaml +spec: + defaultTTL: "1h" +``` + +#### spec.maxTTL + +`spec.maxTTL` is an `optional` field that specifies the maximum TTL for the leases associated with this role. Accepts time suffixed strings ("1h") or an integer number of seconds. +Defaults to system/engine default TTL time. + +```yaml +spec: + maxTTL: "1h" +``` + +#### spec.revocationStatements + +`spec.revocationStatements` is an `optional` field that specifies +a list of database statements to be executed to revoke a user. +See [here](https://www.vaultproject.io/api/secret/databases/mongodb.html#revocation_statements) for Vault documentation. + +### MongoDBRole Status + +`status` shows the status of the MongoDBRole. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, + which is updated on mutation by the API Server. + +- `phase`: Indicates whether the role successfully applied to Vault or not. + +- `conditions` : Represent observations of a MongoDBRole. diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mysql.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mysql.md new file mode 100644 index 000000000..2adca9e6b --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mysql.md @@ -0,0 +1,135 @@ +--- +title: MySQLRole | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: mysql-database-crds + name: MySQLRole + parent: database-crds-concepts + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# MySQLRole + +## What is MySQLRole + +A `MySQLRole` is a Kubernetes `CustomResourceDefinition` (CRD) which allows a user to create a database secret engine role in a Kubernetes native way. + +When a `MySQLRole` is created, the KubeVault operator creates a +[role](https://www.vaultproject.io/api/secret/databases/index.html#create-role) according to the specification. +If the user deletes the `MySQLRole` CRD, then the respective role will also be deleted from Vault. + +![MySQLRole CRD](/docs/v2025.11.21/images/concepts/mysql_role.svg) + +## MySQLRole CRD Specification + +Like any official Kubernetes resource, a `MySQLRole` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `MySQLRole` object is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: MySQLRole +metadata: + name: mysql-role + namespace: demo +spec: + secretEngineRef: + name: sql-secret-engine + creationStatements: + - "CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';" + - "GRANT SELECT ON *.* TO '{{name}}'@'%';" +status: + observedGeneration: 1 + phase: Success +``` + +> Note: To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}` + +Here, we are going to describe the various sections of the `MySQLRole` crd. + +### MySQLRole Spec + +MySQLRole `spec` contains information that necessary for creating a database role. + +```yaml +spec: + secretEngineRef: + name: + path: + defaultTTL: + maxTTL: + creationStatements: + - "statement-0" + - "statement-1" + revocationStatements: + - "statement-0" +``` + +MySQLRole spec has the following fields: + +#### spec.secretEngineRef + +`spec.secretEngineRef` is a `required` field that specifies the name of a `SecretEngine`. + +```yaml +spec: + secretEngineRef: + name: sql-secret-engine +``` + +#### spec.creationStatements + +`spec.creationStatements` is a `required` field that specifies a list of database statements executed to create and configure a user. +The `{{name}}` and `{{password}}` values will be substituted by Vault. + +```yaml +spec: + creationStatements: + - "CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';" + - "GRANT SELECT ON *.* TO '{{name}}'@'%';" +``` + +#### spec.defaultTTL + +`spec.defaultTTL` is an `optional` field that specifies the TTL for the leases associated with this role. +Accepts time suffixed strings ("1h") or an integer number of seconds. Defaults to system/engine default TTL time. + +```yaml +spec: + defaultTTL: "1h" +``` + +#### spec.maxTTL + +`spec.maxTTL` is an `optional` field that specifies the maximum TTL for the leases associated with this role. +Accepts time suffixed strings ("1h") or an integer number of seconds. Defaults to system/engine default TTL time. + +```yaml +spec: + maxTTL: "1h" +``` + +#### spec.revocationStatements + +`spec.revocationStatements` is an `optional` field that specifies a list of database statements to be executed to revoke a user. The `{{name}}` value will be substituted. If not provided defaults to a generic drop user statement. + +### MySQLRole Status + +`status` shows the status of the MySQLRole. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, + which is updated on mutation by the API Server. + +- `phase`: Indicates whether the role successfully applied to Vault or not. + +- `conditions` : Represent observations of a MySQLRole. diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/postgresrole.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/postgresrole.md new file mode 100644 index 000000000..15424378d --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/postgresrole.md @@ -0,0 +1,147 @@ +--- +title: PostgresRole | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: postgresrole-database-crds + name: PostgresRole + parent: database-crds-concepts + weight: 20 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# PostgresRole + +## What is PostgresRole + +A `PostgresRole` is a Kubernetes `CustomResourceDefinition` (CRD) which allows a user to create a database secret engine role in a Kubernetes native way. + +When a `PostgresRole` is created, the KubeVault operator creates a [role](https://www.vaultproject.io/api/secret/databases/index.html#create-role) according to specification. +If the user deletes the `PostgresRole` CRD, then the respective role will also be deleted from Vault. + +![PostgresRole CRD](/docs/v2025.11.21/images/concepts/postgres_role.svg) + +## PostgresRole CRD Specification + +Like any official Kubernetes resource, a `PostgresRole` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `PostgresRole` object is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: PostgresRole +metadata: + name: pg-role + namespace: demo +spec: + secretEngineRef: + name: vault-app + creationStatements: + - "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';" + - "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" +status: + observedGeneration: 1 + phase: Success +``` + +> Note: To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}` + +Here, we are going to describe the various sections of the `PostgresRole` crd. + +### PostgresRole Spec + +PostgresRole `spec` contains information that necessary for creating a database role. + +```yaml +spec: + secretEngineRef: + name: + path: + defaultTTL: + maxTTL: + creationStatements: + - "statement-0" + - "statement-1" + revocationStatements: + - "statement-0" + rollbackStatements: + - "statement-0" + renewStatements: + - "statement-0" +``` + +PostgresRole spec has the following fields: + +#### spec.secretEngineRef + +`spec.secretEngineRef` is a `required` field that specifies the name of a `SecretEngine`. + +```yaml +spec: + secretEngineRef: + name: pg-secret-engine +``` + +#### spec.creationStatements + +`spec.creationStatements` is a `required` field that specifies a list of database statements executed to create and configure a user. +The `{{name}}`, `{{password}}` and `{{expiration}}` values will be substituted by Vault. + +```yaml +spec: + creationStatements: + - "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';" + - "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" +``` + +#### spec.defaultTTL + +`spec.defaultTTL` is an `optional` field that specifies the TTL for the leases associated with this role. +Accepts time suffixed strings ("1h") or an integer number of seconds. Defaults to system/engine default TTL time. + +```yaml +spec: + defaultTTL: "1h" +``` + +#### spec.maxTTL + +`spec.maxTTL` is an `optional` field that specifies the maximum TTL for the leases associated with this role. +Accepts time suffixed strings ("1h") or an integer number of seconds. Defaults to system/engine default TTL time. + +```yaml +spec: + maxTTL: "1h" +``` + +#### spec.revocationStatements + +`spec.revocationStatements` is an `optional` field that specifies a list of database statements to be executed to revoke a user. The `{{name}}` value will be substituted. If not provided defaults to a generic drop user statement. + +#### spec.rollbackStatements + +`spec.rollbackStatements` is an `optional` field that specifies a list of database statements to be executed +rollback a create operation in the event of an error. Not every plugin type will support this functionality. + +#### spec.renewStatements + +`spec.renewStatements` is an `optional` field that specifies a list of database statements to be executed to renew a user. Not every plugin type will support this functionality. + +### PostgresRole Status + +`status` shows the status of the PostgresRole. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, + which is updated on mutation by the API Server. + +- `phase`: Indicates whether the role successfully applied to Vault or not. + +- `conditions` : Represent observations of a PostgresRole. diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/redis.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/redis.md new file mode 100644 index 000000000..7f9860f09 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/redis.md @@ -0,0 +1,132 @@ +--- +title: RedisRole | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: redis-database-crds + name: RedisRole + parent: database-crds-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# RedisRole + +## What is RedisRole + +A `RedisRole` is a Kubernetes `CustomResourceDefinition` (CRD) which allows a user to create a Redis database secret engine role in a Kubernetes native way. + +When a `RedisRole` is created, the KubeVault operator creates a Vault [role](https://www.vaultproject.io/api/secret/databases/index.html#create-role) according to the specification. +If the user deletes the `RedisRole` CRD, then the respective role will also be deleted from Vault. + +![RedisRole CRD](/docs/v2025.11.21/images/concepts/redis_role.svg) + +## RedisRole CRD Specification + +Like any official Kubernetes resource, a `RedisRole` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `RedisRole` object is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: RedisRole +metadata: + name: rd-role + namespace: demo +spec: + secretEngineRef: + name: redis-secret-engine + creationStatements: + - "statement-0" + - "statement-1" +status: + observedGeneration: 1 + phase: Success +``` + +> Note: To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}` + +Here, we are going to describe the various sections of the `RedisRole` crd. + +### RedisRole Spec + +RedisRole `spec` contains information that necessary for creating a database role. + +```yaml +spec: + secretEngineRef: + name: + creationStatements: + - "statement-0" + - "statement-1" + revocationStatements: + - "statement-0" +``` + +RedisRole spec has the following fields: + +#### spec.secretEngineRef + +`spec.secretEngineRef` is a `required` field that specifies the name of a `SecretEngine`. + +```yaml +spec: + secretEngineRef: + name: redis-secret-engine +``` + +#### spec.creationStatements + +`spec.creationStatements` is a `required` field that specifies a list of database statements executed to create and configure a user. +See in [here](https://developer.hashicorp.com/vault/api-docs/secret/databases/redis#creation_statements) for Vault documentation. + +```yaml +spec: + creationStatements: + - '["~*", "+@read","+@write"]' +``` + +#### spec.defaultTTL + +`spec.defaultTTL` is an `optional` field that specifies the TTL for the leases associated with this role. Accepts time suffixed strings ("1h") or an integer number of seconds. + Defaults to system/engine default TTL time. + +```yaml +spec: + defaultTTL: "1h" +``` + +#### spec.maxTTL + +`spec.maxTTL` is an `optional` field that specifies the maximum TTL for the leases associated with this role. Accepts time suffixed strings ("1h") or an integer number of seconds. +Defaults to system/engine default TTL time. + +```yaml +spec: + maxTTL: "1h" +``` + +#### spec.revocationStatements + +`spec.revocationStatements` is an `optional` field that specifies +a list of database statements to be executed to revoke a user. +See [here](https://www.vaultproject.io/api/secret/databases/redis.html#revocation_statements) for Vault documentation. + +### RedisRole Status + +`status` shows the status of the RedisRole. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, + which is updated on mutation by the API Server. + +- `phase`: Indicates whether the role successfully applied to Vault or not. + +- `conditions` : Represent observations of a RedisRole. diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/gcp-secret-engine/_index.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/gcp-secret-engine/_index.md new file mode 100755 index 000000000..433af457b --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/gcp-secret-engine/_index.md @@ -0,0 +1,17 @@ +--- +title: Concepts | GCP Secret Engine +menu: + docs_v2025.11.21: + identifier: gcp-crds-concepts + name: GCP + parent: secret-engine-crds-concepts + weight: 40 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/gcp-secret-engine/gcprole.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/gcp-secret-engine/gcprole.md new file mode 100644 index 000000000..3afdc3150 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/gcp-secret-engine/gcprole.md @@ -0,0 +1,139 @@ +--- +title: GCPRole | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: gcprole-secret-engine-crds + name: GCPRole + parent: gcp-crds-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# GCPRole + +## What is GCPRole + +A `GCPRole` is a Kubernetes `CustomResourceDefinition` (CRD) which allows a user to create a GCP secret engine role in a Kubernetes native way. + +When a `GCPRole` is created, the KubeVault operator [configures](https://www.vaultproject.io/docs/secrets/gcp/index.html#setup) a Vault roleset. +The rolesets determine the permissions that Service Account credentials generated by Vault will have on GCP resources. If the user deletes the `GCPRole` CRD, then the respective role will also be deleted from Vault. + +For maintaining similarity with other secret engines we will refer **roleset as role** in the following description. + +![GCPRole CRD](/docs/v2025.11.21/images/concepts/gcp_role.svg) + +## GCPRole CRD Specification + +Like any official Kubernetes resource, a `GCPRole` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `GCPRole` object is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: GCPRole +metadata: + name: gcp-role + namespace: demo +spec: + secretEngineRef: + name: gcp-secret-engine + secretType: access_token + project: ackube + bindings: 'resource "//cloudresourcemanager.googleapis.com/projects/ackube" { + roles = ["roles/viewer"] + }' + tokenScopes: ["https://www.googleapis.com/auth/cloud-platform"] +status: + observedGeneration: 1 + phase: Success +``` + +> Note: To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}` + +Here, we are going to describe the various sections of the `GCPRole` crd. + +### GCPRole Spec + +GCPRole `spec` contains the necessary information required to create a GCP secret engine role. + +```yaml +spec: + secretEngineRef: + name: + path: + secretType: + project: + bindings: + tokenScopes: +``` + +GCPRole spec has the following fields: + +#### spec.secretEngineRef + +`spec.secretEngineRef` is a `required` field that specifies the name of a `SecretEngine`. + +```yaml +spec: + secretEngineRef: + name: gcp-secret-engine +``` + +#### spec.secretType + +`spec.secretType` is a `required` field that specifies the type of secret generated for this roleset. Accepted values: `access_token`, `service_account_key`. + +```yaml +spec: + secretType: access_token +``` + +#### spec.project + +`spec.project` is a `required` field that specifies the name of the GCP project where roleset's service account belongs to. + +```yaml +spec: + project: ackube +``` + +#### spec.bindings + +`spec.bindings` is a `required` field that specifies the bindings configuration string. + +```yaml +spec: + bindings: 'resource "//cloudresourcemanager.googleapis.com/projects/ackube" { + roles = ["roles/viewer"] + }' +``` + +#### spec.tokenScopes + +`spec.tokenScopes` is an `optional` field that specifies the list of +OAuth scopes to assign to `access_token` secrets generated under this role + set (`access_token` role sets only) + +```yaml +spec: + tokenScopes: ["https://www.googleapis.com/auth/cloud-platform"] +``` + +### GCPRole Status + +`status` shows the status of the GCPRole. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, which is updated on mutation by the API Server. + +- `phase`: Indicates whether the role successfully applied to Vault or not. + +- `conditions` : Represent observations of a GCPRole. diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/pki-secret-engine/_index.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/pki-secret-engine/_index.md new file mode 100644 index 000000000..ec014056d --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/pki-secret-engine/_index.md @@ -0,0 +1,17 @@ +--- +title: Concepts | PKI Secret Engine +menu: + docs_v2025.11.21: + identifier: pki-crds-concepts + name: PKI + parent: secret-engine-crds-concepts + weight: 50 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/pki-secret-engine/pkirole.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/pki-secret-engine/pkirole.md new file mode 100644 index 000000000..fc0e68be8 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/pki-secret-engine/pkirole.md @@ -0,0 +1,145 @@ +--- +title: PKIRole | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: pkirole-secret-engine-crds + name: PKIRole + parent: pki-crds-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# PKIRole + +## What is PKIRole + +An `PKIRole` is a Kubernetes `CustomResourceDefinition` (CRD) which allows a user to create PKI secret engine role in a Kubernetes native way. + +When an `PKIRole` is created, the KubeVault operator [configures](https://www.vaultproject.io/docs/secrets/pki/index.html#setup) a Vault role that maps to a set of permissions in PKI as well as an PKI credential type. When users generate credentials, they are generated against this role. If the user deletes the `PKIRole` CRD, +then the respective role will also be deleted from Vault. + +![PKIRole CRD](/docs/v2025.11.21/images/concepts/pki_role.svg) + +## PKIRole CRD Specification + +Like any official Kubernetes resource, a `PKIRole` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `PKIRole` object is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: PKIRole +metadata: + name: pki-role + namespace: demo +spec: + secretEngineRef: + name: pki-secret-engine + allowedDomains: + - "kubevault.com" + allowSubdomains: true + maxTTL: "720h" + additionalPayload: + "allow_ip_sans": "true" +``` + +> Note: To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}` + +Here, we are going to describe the various sections of the `PKIRole` crd. + +### PKIRole Spec + +PKIRole `spec` contains role information. + +```yaml +spec: + secretEngineRef: + name: + allowedDomains: + allowSubdomains: + defaultTTL: + maxTTL: + additionalPayload: + "key": "value" +``` + +`PKIRole` spec has the following fields: + +#### spec.secretEngineRef + +`spec.secretEngineRef` is a `required` field that specifies the name of a `SecretEngine`. + +```yaml +spec: + secretEngineRef: + name: pki-secret-engine +``` + +#### spec.allowedDomains + +`spec.allowedDomains` is a `required` field that specifies the domains this role is allowed to issue certificates for + +```yaml +spec: + allowedDomains: + - "kubevault.com" +``` + +#### spec.allowSubdomains + +`spec.allowSubdomains` is an `optional` field that specifies the if subdomains is allowed. + +```yaml +spec: + allowSubdomains: true +``` + +#### spec.defaultTTL + +`spec.defaultTTL` is an `optional` field that specifies the default TTL for certificates. + +```yaml +spec: + maxTTL: "1h" +``` + +#### spec.maxTTL + +`spec.maxTTL` is an `optional` field that specifies the max allowed TTL for certificates. + +```yaml +spec: + maxTTL: "1h" +``` + +#### spec.additionalPayload + +`spec.additionalPayload` is an `optional` field which can used to provide any key value of [vault-api](https://developer.hashicorp.com/vault/api-docs/secret/pki#create-update-role) +which will be used to create the role. + +```yaml +spec: + additionalPayload: + "key1": "value1" + "key2": "value2" + +``` + +### PKIRole Status + +`status` shows the status of the PKIRole. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, which is updated on mutation by the API Server. + +- `phase`: Indicates whether the role successfully applied to Vault or not. + +- `conditions` : Represent observations of an PKIRole. diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/secret-access-request.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/secret-access-request.md new file mode 100644 index 000000000..12be02370 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/secret-access-request.md @@ -0,0 +1,190 @@ +--- +title: Secret Access Request +menu: + docs_v2025.11.21: + identifier: secret-access-request-secret-engine-crds + name: SecretAccessRequest + parent: secret-engine-crds-concepts + weight: 11 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# SecretAccessRequest + +## What is SecretAccessRequest + +A `SecretAccessRequest` is a Kubernetes `CustomResourceDefinition` (CRD) which allows a user to request a Vault server for credentials in a Kubernetes native way. +A `SecretAccessRequest` can be created under various `roleRef` e.g: `AWSRole`, `GCPRole`, `ElasticsearchRole`, `MongoDBRole`, etc. A `SecretAccessRequest` has three different phases e.g: +`WaitingForApproval`, `Approved`, `Denied`. If `SecretAccessRequest` is approved, then the KubeVault operator will issue credentials and create Kubernetes secret containing credentials. The secret name will be specified in `status.secret.name` field. + +Once a `SecretAccessRequest` phase is `Approved`, it can't be `Denied`. A `Denied` phase will automatically change to `WaitingForApproval` phase if any changes in `SecretAccessRequest.spec` is made by the user. + + +![SecretAccessRequest CRD](/docs/v2025.11.21/images/concepts/secret_access_request.svg) + +KubeVault operator performs the following operations when a `SecretAccessRequest` CRD is created: + +- Checks whether `status.phase` is `Approved` or not +- If Approved, requests the Vault server for credentials +- Creates a Kubernetes Secret which contains the credentials +- Sets the name of the k8s secret to SecretAccessRequest's `status.secret.name` +- Sets the namespace of the k8s secret to SecretAccessRequest's `status.secret.namespace` +- Assigns read permissions on that Kubernetes secret to specified subjects or user identities + +## SecretAccessRequest CRD Specification + +Like any official Kubernetes resource, a `SecretAccessRequest` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `SecretAccessRequest` object for the `AWSRole` is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: aws-cred-req + namespace: dev +spec: + roleRef: + kind: AWSRole + name: aws-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: test +``` + +Here, we are going to describe the various sections of the `SecretAccessRequest` CRD. + +### SecretAccessRequest Spec + +SecretAccessRequest `spec` contains information about the role and the subjects. + +```yaml +spec: + roleRef: + apiGroup: + kind: + name: + subjects: + - kind: + apiGroup: + name: + namespace: + ttl: +``` + +`SecretAccessRequest` spec has the following fields: + +#### spec.roleRef + +`spec.roleRef` is a `required` field that specifies the role against which credentials will be issued. + +It has the following fields: + +- `roleRef.apiGroup` : `Optional`. Specifies the APIGroup of the resource being referenced. + +- `roleRef.kind` : `Required`. Specifies the kind of the resource being referenced. + +- `roleRef.name` : `Required`. Specifies the name of the object being referenced. + + +```yaml +spec: + roleRef: + kind: AWSRole + name: aws-role +``` + +#### spec.subjects + +`spec.subjects` is a `required` field that contains a list of references to the object or user identities on whose behalf this request is made. These object or user identities will have read access to the k8s credential secret. This can either hold a direct API object reference or a value for non-objects such as user and group names. + +It has the following fields: + +- `kind` : `Required`. Specifies the kind of object being referenced. Values defined by + these API groups are "User", "Group", and "ServiceAccount". If the Authorizer does not + recognize the kind value, the Authorizer will report an error. + +- `apiGroup` : `Optional`. Specifies the APIGroup that holds the API group of the referenced subject. + Defaults to `""` for ServiceAccount subjects. + +- `name` : `Required`. Specifies the name of the object being referenced. + +- `namespace`: `Required`. Specifies the namespace of the object being referenced. + +```yaml +spec: + subjects: + - kind: ServiceAccount + name: sa + namespace: demo +``` + +#### spec.ttl + +`spec.ttl` is an `optional` field that specifies the TTL for the use +of the STS token. This is specified as a string with a duration suffix. + +```yaml +spec: + ttl: "1h" +``` + +### SecretAccessRequest Status + +`status` shows the status of the `SecretAccessRequest`. It is managed by the KubeVault operator. It contains the following fields: + +- `secret`: + - `secret.name`: Specifies the name of the secret containing the credential. + - `secret.namespace`: Specifies the namespace of the secret containing the credential. + +- `lease`: Contains lease information of the issued credential. + +- `conditions` : Represent observations of a `SecretAccessRequest`. It has the following fields: + - `conditions[].type` : Specifies request approval state. Supported type: `Approved` and `Denied`, `Available`. + - `conditions[].status` : Specifies request approval status. Supported type: `True`, `False`. + - `conditions[].reason` : Specifies brief reason for the request state. + - `conditions[].message` : Specifies human-readable message with details about the request state. + - `conditions[].observerGeneration`: Specifies ObserverGeneration for the request state. + +- `phase` : Represent the phase of the `SecretAccessRequest`. Supported type: `Approved` and `Denied`, `WaitingForApproval`. + +`Approved` `SecretAccessRequest.status` may look like this: + +```yaml +status: + conditions: + - lastTransitionTime: "2021-09-28T09:36:45Z" + message: 'This was approved by: kubectl vault approve secretaccessrequest' + observedGeneration: 1 + reason: KubectlApprove + status: "True" + type: Approved + - lastTransitionTime: "2021-09-28T09:36:49Z" + message: The requested credentials successfully issued. + observedGeneration: 1 + reason: SuccessfullyIssuedCredential + status: "True" + type: Available + lease: + duration: 1h0m0s + id: k8s.-.aws.dev.aws-secret-engine/creds/k8s.-.dev.aws-role/ACUzSSp5aLVBzNhoqe6wEqaW + renewable: true + observedGeneration: 1 + phase: Approved + secret: + name: aws-cred-req-92m0n9 + namespace: dev + +``` + +> Note: Credential will be issued only if the `status.phase` is `Approved`. Otherwise, the KubeVault operator will not issue any credentials. \ No newline at end of file diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/secret-role-binding.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/secret-role-binding.md new file mode 100644 index 000000000..9f2aafaae --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/secret-role-binding.md @@ -0,0 +1,328 @@ +--- +title: Secret Role Binding +menu: + docs_v2025.11.21: + identifier: secret-role-binding-secret-engine-crds + name: SecretRoleBinding + parent: secret-engine-crds-concepts + weight: 12 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# SecretRoleBinding + +## What is SecretRoleBinding + +A `SecretRoleBinding` is a Kubernetes `CustomResourceDefinition` (CRD) which allows a user to bind a set of roles to a set of users. +Using the `SecretRoleBinding` it's possible to bind various roles e.g: `AWSRole`, `GCPRole`, `ElasticsearchRole`, `MongoDBRole`, etc. to Kubernetes ServiceAccounts. +A `SecretRoleBinding` has three different phases e.g: `Processing`, `Success`, `Failed`. Once a `SecretRoleBinding` is successful, it will create a `VaultPolicy` and a `VaultPolicyBinding`. + + +## SecretRoleBinding CRD Specification + +Like any official Kubernetes resource, a `SecretRoleBinding` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. +A sample `SecretRoleBinding` object that binds `AWSRole` to a Kubernetes `ServiceAccount` is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-r-binding + namespace: dev +spec: + roles: + - kind: AWSRole + name: aws-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: test +``` + +Here, we are going to describe the various sections of the `SecretRoleBinding` CRD. + +### SecretRoleBinding Spec + +SecretAccessRequest `spec` contains information about the role and the subjects. + +```yaml +spec: + roles: + - kind: + name: + subjects: + - kind: + name: + namespace: +``` + +`SecretRoleBinding` spec has the following fields: + +#### spec.roles + +`spec.roles` is a `required` field that specifies the roles list for which the `VaultPolicy` will be created. + +It has the following fields: + +- `roleRef.apiGroup` : `Optional`. Specifies the APIGroup of the resource being referenced. + +- `roleRef.kind` : `Required`. Specifies the kind of the resource being referenced. + +- `roleRef.name` : `Required`. Specifies the name of the object being referenced. + + +```yaml +spec: + roles: + - kind: + name: +``` + +#### spec.subjects + +`spec.subjects` is a `required` field that contains a list of references to the object or user identities on whose behalf this request is made. These object or user identities will have read access to the k8s credential secret. This can either hold a direct API object reference or a value for non-objects such as user and group names. + +It has the following fields: + +- `kind` : `Required`. Specifies the kind of object being referenced. Values defined by + these API groups are "User", "Group", and "ServiceAccount". If the Authorizer does not + recognize the kind value, the Authorizer will report an error. + +- `apiGroup` : `Optional`. Specifies the APIGroup that holds the API group of the referenced subject. + Defaults to `""` for ServiceAccount subjects. + +- `name` : `Required`. Specifies the name of the object being referenced. + +- `namespace`: `Optional`. Specifies the namespace of the object being referenced. + +```yaml +spec: + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: test +``` + +### SecretRoleBinding Status + +`status` shows the status of the `SecretRoleBinding`. It contains the following fields: + +- `conditions` : Represent observations of a `SecretAccessRequest`. It has the following fields: + - `conditions[].type` : Specifies request approval state. Supported type: `VaultPolicySuccess` and `VaultPolicyBindingSuccess`, `SecretRoleBindingSuccess`. + - `conditions[].status` : Specifies request approval status. Supported type: `True`, `False`. + - `conditions[].reason` : Specifies brief reason for the request state. + - `conditions[].message` : Specifies human-readable message with details about the request state. + - `conditions[].observerGeneration`: Specifies ObserverGeneration for the request state. + +- `phase` : Represent the phase of the `SecretRoleBinding`. Supported type: `Success` and `Failed`, `Processing`. + +- `policyRef` : Represent the `VaultPolicy` created by the `SecretRoleBinding`. + - `policyRef.name`: The name of the `VaultPolicy` created by the `SecretRoleBinding`. + - `policyRef.namespace`: The namespace of the `VaultPolicy` created by the `SecretRoleBinding`. + +- `policyBindingRef` : Represent the `VaultPolicyBinding` created by the `SecretRoleBinding`. + - `policyRef.name`: The name of the `VaultPolicyBinding` created by the `SecretRoleBinding`. + - `policyRef.namespace`: The namespace of the `VaultPolicyBinding` created by the `SecretRoleBinding`. + + +A Successful `SecretAccessRequest.status` may look like this: + +```yaml +status: + conditions: + - lastTransitionTime: "2021-09-28T12:56:35Z" + message: VaultPolicy phase is Successful + observedGeneration: 1 + reason: VaultPolicySucceeded + status: "True" + type: VaultPolicySuccess + - lastTransitionTime: "2021-09-28T12:56:35Z" + message: VaultPolicyBinding is Successful + observedGeneration: 1 + reason: VaultPolicyBindingSucceeded + status: "True" + type: VaultPolicyBindingSuccess + - lastTransitionTime: "2021-09-28T12:56:35Z" + message: SecretRoleBinding is Successful + observedGeneration: 1 + reason: SecretRoleBindingSucceeded + status: "True" + type: SecretRoleBindingSuccess + observedGeneration: 1 + phase: Success + policyBindingRef: + name: srb-dev-secret-r-binding + namespace: demo + policyRef: + name: srb-dev-secret-r-binding + namespace: demo + +``` + +#### SecretRoleBinding status.policyRef + +We can get the `VaultPolicy` if the `SecretRoleBinding` phase is `Success`: + +```bash +$ kubectl get vaultpolicy -n demo srb-dev-secret-r-binding -oyaml +``` +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + annotations: + secretrolebindings.engine.kubevault.com/name: secret-r-binding + secretrolebindings.engine.kubevault.com/namespace: dev + creationTimestamp: "2021-09-28T13:04:15Z" + finalizers: + - kubevault.com + generation: 1 + name: srb-dev-secret-r-binding + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: b73a5a72-d575-4b91-8e95-938828268535 + resourceVersion: "53571" + uid: b4a2ba18-66c3-4f3c-aa35-71b0d66c845f +spec: + policyDocument: | + + path "/k8s.-.aws.dev.aws-secret-engine/creds/k8s.-.dev.aws-role" { + capabilities = ["read"] + } + + path "/k8s.-.aws.dev.aws-secret-engine/sts/k8s.-.dev.aws-role" { + capabilities = ["create", "update"] + } + vaultRef: + name: vault +status: + conditions: + - lastTransitionTime: "2021-09-28T13:04:15Z" + message: policy is ready to use + reason: Provisioned + status: "True" + type: Available + observedGeneration: 1 + phase: Success + +``` + +#### VaultPolicy spec + +- `spec.policyDocument`: contains the document of permissions that are given to the users by `SecretRoleBinding`. +- `spec.vaultRef`: contains the Vault reference. + +```yaml +spec: + policyDocument: | + + path "/k8s.-.aws.dev.aws-secret-engine/creds/k8s.-.dev.aws-role" { + capabilities = ["read"] + } + + path "/k8s.-.aws.dev.aws-secret-engine/sts/k8s.-.dev.aws-role" { + capabilities = ["create", "update"] + } + vaultRef: + name: vault +``` + + +#### SecretRoleBinding status.policyBindingRef + +We can get the `VaultPolicyBinding` if the `SecretRoleBinding` phase is `Success`: + +```bash +$ kubectl get vaultpolicybinding -n demo srb-dev-secret-r-binding -oyaml +``` +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + annotations: + secretrolebindings.engine.kubevault.com/name: secret-r-binding + secretrolebindings.engine.kubevault.com/namespace: dev + creationTimestamp: "2021-09-28T13:04:15Z" + finalizers: + - kubevault.com + generation: 1 + name: srb-dev-secret-r-binding + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: b73a5a72-d575-4b91-8e95-938828268535 + resourceVersion: "53576" + uid: c37dc7ca-03ca-4191-af6c-fe91e544394a +spec: + policies: + - ref: srb-dev-secret-r-binding + subjectRef: + kubernetes: + name: k8s.-.demo.srb-dev-secret-r-binding + path: kubernetes + serviceAccountNames: + - test-user-account + serviceAccountNamespaces: + - test + vaultRef: + name: vault + vaultRoleName: k8s.-.demo.srb-dev-secret-r-binding +status: + conditions: + - lastTransitionTime: "2021-09-28T13:04:16Z" + message: policy binding is ready to use + reason: Provisioned + status: "True" + type: Available + observedGeneration: 1 + phase: Success + +``` + +#### VaultPolicyBinding spec + +- `spec.policies`: contains the `VaultPolicy` references. +- `spec.subjectRef`: contains the Kubernetes subject reference and the `ServiceAccount` list. +- `spec.vaultRef`: contains the Vault reference. +- `spec.vaultRoleName`: contains the Role Name created by the operator. + +```yaml +spec: + policies: + - ref: srb-dev-secret-r-binding + subjectRef: + kubernetes: + name: k8s.-.demo.srb-dev-secret-r-binding + path: kubernetes + serviceAccountNames: + - test-user-account + serviceAccountNamespaces: + - test + vaultRef: + name: vault + vaultRoleName: k8s.-.demo.srb-dev-secret-r-binding + +``` + +`VaultPolicyBinding.spec.vaultRoleName` is the role name which will be bound of the policies. +This role may be used during the creation of [SecretProviderClass](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#secretproviderclass) for using the [Secrets-store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/introduction.html). This defaults to following format: `k8s.${cluster or -}.${metadata.namespace}.${metadata.name}` + +> Note: Here, the `VaultPolicy` and the `VaultPolicyBinding` both have the same name with prefix `srb` added to them to indicate that they're created by the `SecretRoleBinding` creation. diff --git a/content/docs/v2025.11.21/concepts/secret-engine-crds/secretengine.md b/content/docs/v2025.11.21/concepts/secret-engine-crds/secretengine.md new file mode 100644 index 000000000..bd47c40ca --- /dev/null +++ b/content/docs/v2025.11.21/concepts/secret-engine-crds/secretengine.md @@ -0,0 +1,580 @@ +--- +title: Secret Engine +menu: + docs_v2025.11.21: + identifier: secret-engine-crds + name: SecretEngine + parent: secret-engine-crds-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# SecretEngine + +## What is a SecretEngine + +A `SecretEngine` is a Kubernetes `CustomResourceDefinition` (CRD) which is designed to automate the process of enabling and configuring secret engines in Vault in a Kubernetes native way. + +Secrets engines are components that store, generate, +or encrypt data. Secrets engines are provided some set of data, they take some action on that data, and they return a result. +Secrets engines are enabled at a "path" in Vault. +In this way, each secrets engine defines its paths and properties. To the user, secrets engines behave similar to a virtual filesystem, supporting operations like read, write, and delete. + +When a `SecretEngine` CRD is created, the KubeVault operator will perform the following operations: + +- **Creates** vault policy for the secret engine. The vault policy name follows the naming format:`k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. For example, the policy for GCP secret engine is below: + +```hcl + path "/config" { + capabilities = ["create", "update", "read", "delete"] + } + + path "/roleset/*" { + capabilities = ["create", "update", "read", "delete"] + } + + path "/token/*" { + capabilities = ["create", "update", "read"] + } + + path "/key/*" { + capabilities = ["create", "update", "read"] + } +``` + +- **Updates** the Kubernetes auth role of the default k8s service account created with `VaultServer` with a new policy. The new policy will be merged with previous policies. + +- **Enables** the secrets engine at a given path. By default, they are enabled at their "type" (e.g. "aws" is enabled at "aws/"). + +- **Configures** the secret engine with the given configuration. + +## SecretEngine CRD Specification + +Like any official Kubernetes resource, a `SecretEngine` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `SecretEngine` object is shown below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: first-secret-engine + namespace: demo +spec: + vaultRef: + name: vault + gcp: + credentialSecret: "gcp-cred" +status: + observedGeneration: 1 + phase: Success +``` + +Here, we are going to describe the various sections of the `SecretEngine` crd. + +### SecretEngine Spec + +SecretEngine `.spec` contains information about the secret engine configuration and an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) reference which is used to connect with a Vault server. + +SecretEngine `.spec` has the following fields: + +#### spec.vaultRef + +`spec.vaultRef` is a `required` field that specifies an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) +reference which is used to connect with a Vault server. AppBinding must be on the same namespace of the secret engine crd. + +```yaml +spec: + vaultRef: + name: vault +``` + +#### spec.path + +`spec.path` will be set by the KubeVault operator. + +Secret engines are enabled at a "path" in Vault. When a request comes to Vault, the router automatically routes anything with the route prefix to the secret engine. Since operator configures a secret engine to a specified path with SecretEngine resource, you can provide **only one secret engine configuration** out of the following ones: + +- `spec.aws` : Specifies aws secret engine configuration + +- `spec.azure`: Specifies azure secret engine configuration + +- `spec.pki`: Specifies pki secret engine configuration + +- `spec.gcp`: Specifies gcp secret engine configuration + +- `spec.postgres`: Specifies database(postgres) secret engine configuration + +- `spec.mongodb`: Specifies database(mongodb) secret engine configuration + +- `spec.mysql`: Specifies database(mysql) secret engine configuration + +- `spec.elasticsearch`: Specifies database(elasticsearch) secret engine configuration + +- `spec.redis`: Specifies database(redis) secret engine configuration + +#### spec.aws + +`spec.aws` specifies the configuration required to configure +AWS secret engine. [See more](https://www.vaultproject.io/api/secret/aws/index.html#parameters) + +```yaml +spec: + aws: + credentialSecret: aws-cred + region: us-east-1 + leaseConfig: + lease: 1h + leaseMax: 1h +``` + +- `aws.credentialSecret` : `Required`. Specifies the k8s secret name that contains AWS access key ID and secret access key + + ```yaml + spec: + aws: + credentialSecret: + ``` + + The `data` field of the secret must contain the following key-value pairs: + + ```yaml + data: + access_kay: + secret_key: + ``` + +- `aws.region` : `Required`. Specifies the AWS region. + +- `aws.iamEndpoint` : `Optional`. Specifies a custom HTTP IAM endpoint to use. + +- `aws.stsEndpoint` : `Optional`. Specifies a custom HTTP STS endpoint to use. + +- `config.maxRetries` : `Optional`. Specifies the number of max retries the client should use for recoverable errors. + +- `aws.leaseConfig` : `Optional`. Specifies the lease configuration. + + ```yaml + config: + leaseConfig: + lease: 1h + leaseMax: 1h + ``` + +It has the following fields: + + - `leaseConfig.lease` : `Optional`. Specifies the lease value. Accepts time suffixed strings (eg, "1h"). + + - `leaseConfig.leaseMax` : `Optional`. Specifies the maximum lease value. Accepts time suffixed strings (eg, "1h"). + +#### spec.azure + +`spec.azure` specifies the configuration required to configure +Azure secret engine. [See more](https://www.vaultproject.io/api/secret/azure/index.html#configure-access) + +```yaml +spec: + azure: + credentialSecret: azure-cred + environment: AzurePublicCloud +``` + +- `credentialSecret` : `Required`. Specifies the k8s secret name containing azure credentials. The `data` field of the mentioned k8s secret can have the following key-value pairs. + + - `subscription-id` : `Required`. Specifies the subscription id for the Azure Active Directory. + + - `tenant-id` : `Required`. Specifies the tenant id for the Azure Active Directory. + + - `client-id` : `Optional`. Specifies the OAuth2 client id to connect to Azure. + + - `client-secret` : `Optional`. Specifies the OAuth2 client secret to connect to Azure. + + ```yaml + data: + subscription-id: + tenant-id: + client-id: + client-secret: + ``` + +- `environment` : `Optional`. Specifies the Azure environment. If not specified, Vault will use Azure Public Cloud. + +#### spec.gcp + +`spec.gcp` specifies the configuration required to configure GCP +secret engine. [See more](https://www.vaultproject.io/api/secret/gcp/index.html#write-config) + +```yaml + spec: + gcp: + credentialSecret: gcp-cred + ttl: 0s + maxTTL: 0s +``` + +- `credentialSecret` : `Required`. Specifies the k8s secret name that contains google application credentials. + + ```yaml + spec: + gcp: + credentialSecret: + ``` + + The `data` field of the mentioned k8s secret must contain the following key-value pair: + + ```yaml + data: + sa.json: + ``` + +- `ttl` : `Optional`. Specifies default config TTL for long-lived credentials (i.e. service account keys). Default value is 0s. + +- `maxTTL` : `Optional`. Specifies the maximum config TTL for long-lived credentials (i.e. service account keys). The default value is 0s. + +#### spec.pki + +`spec.pki` specifies the configuration required to configure +PKI secret engine. [See more](https://developer.hashicorp.com/vault/api-docs/secret/pki#generate-root) + +```yaml +spec: + pki: + isRootCA: false + parentCARef: + name: pki-root + namespace: demo + commonName: "kubevault.com" + ttl: "87600h" + maxLeaseTTL: "487600h" +``` + +- `isRootCA` : `Required`. Specifies if the secret engine will be used as a RootCA + +- `parentCARef` : `Required`. Specifies the namespace and name of the secret engine which will sign the intermediate CA. + +- `commonName` : `Required`. Specifies the requested CN for the certificate. If more than one common_name is desired, specify the alternative names in the `spec.altNames` list. + +- `ttl` : `Optional`. Specifies he requested Time To Live (after which the certificate will be expired). + +- `maxLeaseTTL` : `Optional`. Specifies maximum lease for the certificates. + +#### spec.postgres + +`spec.postgres` specifies the configuration required to configure PostgreSQL database secret engine. [See more](https://www.vaultproject.io/api/secret/databases/postgresql.html#configure-connection) + + ```yaml + spec: + postgres: + databaseRef: + name: + namespace: + pluginName: + allowedRoles: + - "rule1" + - "rule2" + maxOpenConnections: + maxIdleConnections: + maxConnectionLifetime: + ``` + +- `databaseRef` : `Required`. Specifies an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) reference that is required to connect to a PostgreSQL database. It is also used to generate `db_name` (i.e. `/v1/path/config/db_name`) where the database secret engine will be configured at. The name of the `db_name` follows this pattern: `k8s.{clusterName}.{namespace}.{name}`. + + - `name` : `Required`. Specifies the AppBinding name. + + - `namespace` : `Required`. Specifies the AppBinding namespace. + + ```yaml + postgres: + databaseRef: + name: db-app + namespace: demo + ``` + + The generated `db_name` for the above example will be: `k8s.-.demo.db-app`. If the cluster name is empty, it is replaced by "`-`". + +- `pluginName` : `Optional`. Specifies the name of the plugin to use for this connection. + Default plugin name is `postgres-database-plugin`. + + ```yaml + postgres: + pluginName: postgres-database-plugin + ``` + +- `allowedRoles` : `Optional`. Specifies a list of roles allowed to use this connection. + Default to `"*"` (i.e. any role can use this connection). + + ```yaml + postgres: + allowedRoles: + - "readonly" + ``` + +- `maxOpenConnections` : `Optional`. Specifies the maximum number of open connections to + the database. Default value 2. + + ```yaml + postgres: + maxOpenConnections: 3 + ``` + +- `maxIdleConnections` : `Optional`. Specifies the maximum number of idle connections to the database. Zero uses the value of max_open_connections and a negative value disables idle connections. If larger than max_open_connections it will be reduced to be equal. Default value 0. + + ```yaml + postgres: + maxIdleConnections: 1 + ``` + +- `maxConnectionLifetime` : `Optional`. Specifies the maximum amount of time a connection may be reused. If <= 0s connections are reused forever. Default value 0s. + + ```yaml + postgres: + maxConnectionLifetime: 5s + ``` + +#### spec.mongodb + +`spec.mongodb` specifies the configuration required to configure MongoDB database secret engine. [See more](https://www.vaultproject.io/api/secret/databases/mongodb.html#configure-connection) + +```yaml + spec: + mongodb: + databaseRef: + name: + namespace: + pluginName: + allowedRoles: + - "role1" + - "role2" + writeConcern: +``` + +- `databaseRef` : `Required`. Specifies an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) reference that is required to connect to a MongoDB database. It is also used to generate `db_name` (i.e. `/v1/path/config/db_name`) where the database secret engine will be configured at. The naming of `db_name` follows: `k8s.{clusterName}.{namespace}.{name}`. + + - `name` : `Required`. Specifies the AppBinding name. + + - `namespace` : `Required`. Specifies the AppBinding namespace. + + ```yaml + mongodb: + databaseRef: + name: db-app + namespace: demo + ``` + + The generated `db_name` for the above example will be: `k8s.-.demo.db-app`. If the cluster name is empty, it is replaced by "`-`". + +- `pluginName` : `Optional`. Specifies the name of the plugin to use for this connection. +Default plugin name is `mongodb-database-plugin`. + + ```yaml + mongodb: + pluginName: mongodb-database-plugin + ``` + +- `allowedRoles` : `Optional`. Specifies a list of roles allowed to use this connection. + Default to `"*"` (i.e. any role can use this connection). + + ```yaml + mongodb: + allowedRoles: + - "readonly" + ``` + +- `writeConcern` : `Optional`. Specifies the MongoDB write concern. + This is set for the entirety of the session, maintained for the life cycle of the plugin process. Must be a serialized JSON object, + or a base64-encoded serialized JSON object. The JSON payload values map to the values in the Safe struct from the mongo driver. + + ```yaml + mongodb: + writeConcern: `{ \"wmode\": \"majority\", \"wtimeout\": 5000 }` + ``` + +#### spec.mysql + +`spec.mysql` specifies the configuration required to configure MySQL database secret engine. [See more](https://www.vaultproject.io/api/secret/databases/mysql-maria.html#configure-connection) + + ```yaml + spec: + mysql: + databaseRef: + name: + namespace: + pluginName: + allowedRoles: + - "role1" + - "role2" + - ... ... + maxOpenConnections: + maxIdleConnections: + maxConnectionLifetime: + ``` + +- `databaseRef` : `Required`. Specifies an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) reference that is required to connect to a MySQL database. It is also used to generate `db_name` (i.e. `/v1/path/config/db_name`) where the database secret engine will be configured at. The naming of `db_name` follows: `k8s.{clusterName}.{namespace}.{name}`. + + - `name` : `Required`. Specifies the AppBinding name. + + - `namespace` : `Required`. Specifies the AppBinding namespace. + + ```yaml + mysql: + databaseRef: + name: db-app + namespace: demo + ``` + + The generated `db_name` for the above example will be: `k8s.-.demo.db-app`. If the cluster name is empty, it is replaced by "`-`". + +- `pluginName` : `Optional`. Specifies the name of the plugin to use for this connection. + The default plugin name is `mysql-database-plugin`. + + ```yaml + mysql: + pluginName: mysql-database-plugin + ``` + +- `allowedRoles` : `Optional`. Specifies a list of roles allowed to use this connection. + Default to `"*"` (i.e. any role can use this connection). + + ```yaml + mysql: + allowedRoles: + - "readonly" + ``` + +- `maxOpenConnections` : `Optional`. Specifies the maximum number of open connections to the database. Default value 2. + + ```yaml + mysql: + maxOpenConnections: 3 + ``` + +- `maxIdleConnections` : `Optional`. Specifies the maximum number of idle connections to the database. Zero uses the value of max_open_connections and a negative value disables idle connections. If larger than max_open_connections it will be reduced to be equal. Default value 0. + + ```yaml + mysql: + maxIdleConnections: 1 + ``` + +- `maxConnectionLifetime` : `Optional`. Specifies the maximum amount of time a connection may be reused. If <= 0s connections are reused forever. Default value 0s. + + ```yaml + mysql: + maxConnectionLifetime: 5s + ``` + +#### spec.elasticsearch + +`spec.elasticsearch` specifies the configuration required to configure Elasticsearch database secret engine. [See more](https://www.vaultproject.io/api/secret/databases/elasticdb.html#configure-connection) + + ```yaml + spec: + elasticsearch: + databaseRef: + name: + namespace: + pluginName: + allowedRoles: + - "role1" + - "role2" + - ... ... + ``` + +- `databaseRef` : `Required`. Specifies an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) reference that is required to connect to an Elasticsearch database. It is also used to generate `db_name` (i.e. `/v1/path/config/db_name`) where the database secret engine will be configured at. The naming of `db_name` follows: `k8s.{clusterName}.{namespace}.{name}`. + + - `name` : `Required`. Specifies the AppBinding name. + + - `namespace` : `Required`. Specifies the AppBinding namespace. + + ```yaml + elasticsearch: + databaseRef: + name: db-app + namespace: demo + ``` + + The generated `db_name` for the above example will be: `k8s.-.demo.db-app`. If the cluster name is empty, it is replaced by "`-`". + +- `pluginName` : `Optional`. Specifies the name of the plugin to use for this connection. + The default plugin name is `elasticsearch-database-plugin`. + + ```yaml + elasticsearch: + pluginName: elasticsearch-database-plugin + ``` + +- `allowedRoles` : `Optional`. Specifies a list of roles allowed to use this connection. + Default to `"*"` (i.e. any role can use this connection). + + ```yaml + elasticsearch: + allowedRoles: + - "readonly" + ``` + +#### spec.redis +`spec.redis` specifies the configuration required to configure Redis database secret engine. [See more](https://developer.hashicorp.com/vault/api-docs/secret/databases/redis#configure-connection) + + ```yaml + spec: + redis: + databaseRef: + name: + namespace: + pluginName: + allowedRoles: + - "role1" + - "role2" + - ... ... + ``` + +- `databaseRef` : `Required`. Specifies an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) reference that is required to connect to an Redis database. It is also used to generate `db_name` (i.e. `/v1/path/config/db_name`) where the database secret engine will be configured at. The naming of `db_name` follows: `k8s.{clusterName}.{namespace}.{name}`. + + - `name` : `Required`. Specifies the AppBinding name. + + - `namespace` : `Required`. Specifies the AppBinding namespace. + + ```yaml + redis: + databaseRef: + name: db-app + namespace: demo + ``` + + The generated `db_name` for the above example will be: `k8s.-.demo.db-app`. If the cluster name is empty, it is replaced by "`-`". + +- `pluginName` : `Optional`. Specifies the name of the plugin to use for this connection. + The default plugin name is `redis-database-plugin`. + + ```yaml + redis: + pluginName: redis-database-plugin + ``` + +- `allowedRoles` : `Optional`. Specifies a list of roles allowed to use this connection. + Default to `"*"` (i.e. any role can use this connection). + + ```yaml + redis: + allowedRoles: + - "readonly" + ``` + + +### SecretEngine Status + +`status` shows the status of the SecretEngine. It is managed by the KubeVault operator. It contains the following fields: + +- `observedGeneration`: Specifies the most recent generation observed for this resource. It corresponds to the resource's generation, which is updated on mutation by the API Server. + +- `phase`: Indicates whether the secret engine successfully configured in the Vault or not. + +- `conditions` : Represent observations of a SecretEngine. diff --git a/content/docs/v2025.11.21/concepts/tls-encryption/_index.md b/content/docs/v2025.11.21/concepts/tls-encryption/_index.md new file mode 100644 index 000000000..fe033cf9c --- /dev/null +++ b/content/docs/v2025.11.21/concepts/tls-encryption/_index.md @@ -0,0 +1,17 @@ +--- +title: Concepts | Vault Server TLS +menu: + docs_v2025.11.21: + identifier: vault-server-tls + name: Vault Server TLS + parent: concepts + weight: 50 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/tls-encryption/configuration.md b/content/docs/v2025.11.21/concepts/tls-encryption/configuration.md new file mode 100644 index 000000000..3f7f24134 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/tls-encryption/configuration.md @@ -0,0 +1,127 @@ +--- +title: Configure TLS/SSL for VaultServer | KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: vault-tls-concepts + name: TLS/SSL Configuration + parent: vault-server-tls + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Configure TLS/SSL for VaultServer + +`KubeVault` provides support for TLS/SSL for `VaultServer`. This tutorial will show you how to use `KubeVault` to deploy a `VaultServer` with TLS/SSL configuration. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). + +- Install [`cert-manger`](https://cert-manager.io/docs/installation/) v1.4.0 or later to your cluster to manage your SSL/TLS certificates. + +- Install `KubeVault` operator in your cluster following the steps [here](/docs/v2025.11.21/setup/README). + +- To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + + ```bash + $ kubectl create ns demo + namespace/demo created + ``` + +### Deploy VaultServer with TLS/SSL configuration + +As pre-requisite, at first, we are going to create an Issuer/ClusterIssuer. This Issuer/ClusterIssuer is used to create certificates. Then we are going to deploy a VaultServer with TLS/SSL configuration. + +### Create Issuer/ClusterIssuer + +Now, we are going to create an example `Issuer` that will be used throughout the duration of this tutorial. Alternatively, you can follow this [cert-manager tutorial](https://cert-manager.io/docs/configuration/ca/) to create your own `Issuer`. By following the below steps, we are going to create our desired issuer, + +- Start off by generating our ca-certificates using openssl, + +```bash +$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./ca.key -out ./ca.crt -subj "/CN=vault/O=kubevault" +``` + +- create a secret using the certificate files we have just generated, + +```bash +$ kubectl create secret tls vault-ca --cert=ca.crt --key=ca.key --namespace=demo +secret/vault-ca created +``` + +Now, we are going to create an `Issuer` using the `vault-ca` secret that contains the ca-certificate we have just created. Below is the YAML of the `Issuer` cr that we are going to create, + +```yaml +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: vault-issuer + namespace: demo +spec: + ca: + secretName: vault-ca +``` + +Let’s create the `Issuer` cr we have shown above, + +```bash +$ kubectl apply -f issuer.yaml +issuer.cert-manager.io/vault-issuer created +``` + +### Deploy VaultServer with TLS/SSL configuration + +Here, our issuer `vault-issuer` is ready to deploy a `VaultServer` Cluster with TLS/SSL configuration. Below is the YAML for VaultServer that we are going to create, + +```yaml +apiVersion: kubevault.com/v1alpha2 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + tls: + issuerRef: + apiGroup: "cert-manager.io" + kind: Issuer + name: vault-issuer + allowedSecretEngines: + namespaces: + from: All + secretEngines: + - mysql + version: 1.10.3 + replicas: 3 + backend: + raft: + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate +``` + +Here, + +- `spec.tls.issuerRef` refers to the `vault-issuer` issuer. diff --git a/content/docs/v2025.11.21/concepts/tls-encryption/overview.md b/content/docs/v2025.11.21/concepts/tls-encryption/overview.md new file mode 100644 index 000000000..110d3edf0 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/tls-encryption/overview.md @@ -0,0 +1,118 @@ +--- +title: Overview | KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: vault-tls-overview + name: Overview + parent: vault-server-tls + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Overview + +**Prerequisite :** To configure TLS/SSL in `VaultServer`, `KubeVault` uses `cert-manager` to issue certificates. So first you have to make sure that the cluster has `cert-manager` installed. To install `cert-manager` in your cluster following steps [here](https://cert-manager.io/docs/installation/kubernetes/). + +To issue a certificate, the following cr of `cert-manager` is used: + +- `Issuer/ClusterIssuer`: Issuers and ClusterIssuers represent certificate authorities (CAs) that are able to generate signed certificates by honoring certificate signing requests. All cert-manager certificates require a referenced issuer that is in a ready condition to attempt to honor the request. You can learn more details [here](https://cert-manager.io/docs/concepts/issuer/). + +- `Certificate`: `cert-manager` has the concept of Certificates that define the desired x509 certificate which will be renewed and kept up to date. You can learn more details [here](https://cert-manager.io/docs/concepts/certificate/). + +**VaultServer CRD Specification:** + +KubeValt uses the following cr fields to enable SSL/TLS encryption in `VaultServer`. + +```yaml +spec: + tls: + issuerRef: + apiGroup: "cert-manager.io" + kind: Issuer + name: vault-issuer + certificates: + - alias: server + secretName: vautl-server-certs + subject: + organizations: + - kubevault + - alias: client + secretName: vault-client-certs + subject: + organizations: + - kubevault + +``` + +The `spec.tls` contains the following fields: + +- `tls.issuerRef` - is an `optional` field that references to the `Issuer` or `ClusterIssuer` custom resource object of [cert-manager](https://cert-manager.io/docs/concepts/issuer/). It is used to generate the necessary certificate secrets for Elasticsearch. If the `issuerRef` is not specified, the operator creates a self-signed CA and also creates necessary certificate (valid: 365 days) secrets using that CA. + - `apiGroup` - is the group name of the resource that is being referenced. Currently, the only supported value is `cert-manager.io`. + - `kind` - is the type of resource that is being referenced. The supported values are `Issuer` and `ClusterIssuer`. + - `name` - is the name of the resource ( `Issuer` or `ClusterIssuer` ) that is being referenced. + +- `tls.certificates` - is an `optional` field that specifies a list of certificate configurations used to configure the certificates. It has the following fields: + - `alias` - represents the identifier of the certificate. It has the following possible value: + - `server` - is used for the server certificate configuration. + - `client` - is used for the client certificate configuration. + - `storage` - is used for the storage certificate configuration. + - `ca` - is used for the ca certificate configuration. + + - `secretName` - ( `string` | `"-alias-certs"` ) - specifies the k8s secret name that holds the certificates. + + - `subject` - specifies an `X.509` distinguished name (DN). It has the following configurable fields: + - `organizations` ( `[]string` | `nil` ) - is a list of organization names. + - `organizationalUnits` ( `[]string` | `nil` ) - is a list of organization unit names. + - `countries` ( `[]string` | `nil` ) - is a list of country names (ie. Country Codes). + - `localities` ( `[]string` | `nil` ) - is a list of locality names. + - `provinces` ( `[]string` | `nil` ) - is a list of province names. + - `streetAddresses` ( `[]string` | `nil` ) - is a list of street addresses. + - `postalCodes` ( `[]string` | `nil` ) - is a list of postal codes. + - `serialNumber` ( `string` | `""` ) is a serial number. + + For more details, visit [here](https://golang.org/pkg/crypto/x509/pkix/#Name). + + - `duration` ( `string` | `""` ) - is the period during which the certificate is valid. A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as `"300m"`, `"1.5h"` or `"20h45m"`. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + - `renewBefore` ( `string` | `""` ) - is a specifiable time before expiration duration. + - `dnsNames` ( `[]string` | `nil` ) - is a list of subject alt names. + - `ipAddresses` ( `[]string` | `nil` ) - is a list of IP addresses. + - `uris` ( `[]string` | `nil` ) - is a list of URI Subject Alternative Names. + - `emailAddresses` ( `[]string` | `nil` ) - is a list of email Subject Alternative Names. + + +## How TLS/SSL configures in VaultServer + +The following figure shows how `KubeVault` is used to configure TLS/SSL in Postgres. Open the image in a new tab to see the enlarged version. + +Deploying VaultServer with TLS/SSL configuration process consists of the following steps: + +1. At first, a user creates an `Issuer/ClusterIssuer` cr. + +2. Then the user creates a `VaultServer` cr. + +3. `KubeVault` community operator watches for the `VaultServer` cr. + +4. When it finds one, it creates `Secret`, `Service`, etc. for the `VaultServer`. + +5. `KubeVault` operator watches for `VaultServer`(5c), `Issuer/ClusterIssuer`(5b), `Secret` and `Service`(5a). + +6. When it finds all the resources(`VaultServer`, `Issuer/ClusterIssuer`, `Secret`, `Service`), it creates `Certificates` by using `tls.issuerRef` and `tls.certificates` field specification from `VaultServer` cr. + +7. `cert-manager` watches for certificates. + +8. When it finds one, it creates certificate secrets `cert-secrets`(server, client, exporter secrets, etc.) that hold the actual self-signed certificate. + +9. `KubeVault` community operator watches for the Certificate secrets `tls-secrets`. + +10. When it finds all the tls-secret, it creates a `StatefulSet` so that Postgres server is configured with TLS/SSL. + +In the next doc, we are going to show a step by step guide on how to configure a `VaultServer` with TLS/SSL. \ No newline at end of file diff --git a/content/docs/v2025.11.21/concepts/vault-ops-request/_index.md b/content/docs/v2025.11.21/concepts/vault-ops-request/_index.md new file mode 100644 index 000000000..a3ae18516 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-ops-request/_index.md @@ -0,0 +1,17 @@ +--- +title: Vault Ops Request | Concepts | KubeVault +menu: + docs_v2025.11.21: + identifier: ops-request-concepts + name: Vault Ops Request + parent: concepts + weight: 30 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/vault-ops-request/overview.md b/content/docs/v2025.11.21/concepts/vault-ops-request/overview.md new file mode 100644 index 000000000..f3620f9e5 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-ops-request/overview.md @@ -0,0 +1,210 @@ +--- +title: Vault Ops Request Overview | KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: overview-ops-request-concepts + name: Overview + parent: ops-request-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/README). + +# VaultOpsRequest + +## What is VaultOpsRequest + +`VaultOpsRequest` is a Kubernetes `Custom Resource Definitions` (CRD). It provides a declarative configuration for `Vault` administrative operations like restart, reconfigure TLS etc. in a Kubernetes native way. + +## VaultOpsRequest CRD Specifications + +Like any official Kubernetes resource, a `VaultOpsRequest` has `TypeMeta`, `ObjectMeta`, `Spec` and Status sections. + +Here, some sample `VaultOpsRequest` CRs for different administrative operations is given below: + +### Sample `VaultOpsRequest` for restarting `VaultServer`: + +```yaml +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: restart-vault-request + namespace: demo +spec: + restart: {} + type: Restart + vaultRef: + name: vault +status: + conditions: + - lastTransitionTime: "2022-12-04T09:27:07Z" + message: Vault ops request is restarting nodes + observedGeneration: 1 + reason: Restart + status: "True" + type: Restart + - lastTransitionTime: "2022-12-04T09:29:23Z" + message: Successfully restarted all nodes + observedGeneration: 1 + reason: RestartNodes + status: "True" + type: RestartNodes + - lastTransitionTime: "2022-12-04T09:29:23Z" + message: Successfully completed the modification process. + observedGeneration: 1 + reason: Successful + status: "True" + type: Successful + observedGeneration: 1 + phase: Successful + +``` + +### Sample `VaultOpsRequest` Objects for Reconfiguring TLS of the `VaultServer`: + +```yaml +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: vault-ops-add-tls + namespace: demo +spec: + type: ReconfigureTLS + vaultRef: + name: vault + tls: + issuerRef: + name: vault-issuer + kind: Issuer + apiGroup: "cert-manager.io" + certificates: + - alias: client + emailAddresses: + - abc@appscode.com + +``` + +```yaml +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: vault-ops-rotate + namespace: demo +spec: + type: ReconfigureTLS + vaultRef: + name: vault + tls: + rotateCertificates: true + +``` + +```yaml +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: vault-ops-change-issuer + namespace: demo +spec: + type: ReconfigureTLS + vaultRef: + name: vault + tls: + issuerRef: + name: vault-new-issuer + kind: Issuer + apiGroup: "cert-manager.io" + +``` + +```yaml +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: vault-ops-remove + namespace: demo +spec: + type: ReconfigureTLS + vaultRef: + name: vault + tls: + remove: true + +``` + +Here, we are going to describe the various sections of a `VaultOpsRequest` crd. + +A `VaultOpsRequest` object has the following fields in the spec section. + +### spec.vaultRef + +`spec.vaultRef` is a required field that point to the `Vault` object for which the administrative operations will be performed. This field consists of the following sub-field: +- `spec.databaseRef.name` : specifies the name of the `Vault` object. + +### spec.type + +`spec.type` specifies the kind of operation that will be applied to the `VaultServer`. Currently, the following types of operations are allowed in `VaultOpsRequest`. +- Restart +- ReconfigureTLS + +You can perform only one type of operation on a single `VaultOpsRequest` CR. You should not create two `VaultOpsRequest` simultaneously. + +### spec.tls + +If you want to reconfigure the TLS configuration of your `VaultServer` i.e. add TLS, remove TLS, update issuer/cluster issuer or Certificates and rotate the certificates, you have to specify `spec.tls` section. This field consists of the following sub-field: + +- `spec.tls.issuerRef` specifies the issuer name, kind and api group. +- `spec.tls.certificates` specifies the certificates. +- `spec.tls.rotateCertificates` specifies that we want to rotate the certificate of this `VaultServer`. +- `spec.tls.remove` specifies that we want to remove tls from this `VaultServer`. + +### VaultOpsRequest `Status` + +`.status` describes the current state and progress of a `VautlOpsRequest` operation. It has the following fields: + +### status.phase + +`status.phase` indicates the overall phase of the operation for this `VaultOpsRequest`. It can have the following three values: + +| Phase | Meaning | +| ---------- |-------------------------------------------------------------------------------------| +| Successful | KubeVault has successfully performed the operation requested in the VaultOpsRequest | +| Failed | KubeVault has failed the operation requested in the VaultOpsRequest | +| Denied | KubeVault has denied the operation requested in the VaultOpsRequest | + +### status.observedGeneration + +`status.observedGeneration` shows the most recent generation observed by the `VaultOpsRequest` controller. + +### status.conditions + +`status.conditions` is an array that specifies the conditions of different steps of `VaultOpsRequest` processing. Each condition entry has the following fields: +- `types` specifies the type of the condition. `VaultOpsRequest` has the following types of conditions: + +| Type | Meaning | +|------------------------------|-------------------------------------------------------------------------------| +| `Progressing` | Specifies that the operation is now in the progressing state | +| `Successful` | Specifies such a state that the operation on the vault was successful. | +| `ResumeVaultServer` | Specifies such a state that the vault is resumed by the operator | +| `Failed` | Specifies such a state that the operation on the database failed. | +| `UpdateStatefulSetResources` | Specifies such a state that the Statefulset resources has been updated | +| `RestartNodes` | Specifies whether the vault nodes has been restarted or not | +| `CertificateSynced` | Specifies whether the certificates has been synced across all the vault nodes | + + +- The `status` field is a string, with possible values `True`, `False`, and `Unknown`. + - `status` will be `True` if the current transition succeeded. + - `status` will be `False` if the current transition failed. + - `status` will be `Unknown` if the current transition was denied. +- The `message` field is a human-readable message indicating details about the condition. +- The `reason` field is a unique, one-word, CamelCase reason for the condition's last transition. +- The `lastTransitionTime` field provides a timestamp for when the operation last transitioned from one state to another. +- The `observedGeneration` shows the most recent condition transition generation observed by the controller. diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/_index.md b/content/docs/v2025.11.21/concepts/vault-server-crds/_index.md new file mode 100755 index 000000000..03295988e --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/_index.md @@ -0,0 +1,17 @@ +--- +title: Vault Server | Concepts | KubeVault +menu: + docs_v2025.11.21: + identifier: vault-server-crds-concepts + name: Vault Server + parent: concepts + weight: 30 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/appbinding.md b/content/docs/v2025.11.21/concepts/vault-server-crds/appbinding.md new file mode 100644 index 000000000..4307dd029 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/appbinding.md @@ -0,0 +1,285 @@ +--- +title: AppBinding | KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: appbinding-vault-server-crds + name: AppBinding + parent: vault-server-crds-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# AppBinding + +## What is AppBinding + +AppBinding CRD provides a way to specify connection information, credential, and parameters that are necessary for communicating with an app/service. In KubeVault operator, AppBinding used to communicate with externally provisioned Vault, database, etc. + +An `AppBinding` is a Kubernetes `CustomResourceDefinition`(CRD) which points to an application using either its URL (usually for a non-Kubernetes resident service instance) or a Kubernetes service object (if self-hosted in a Kubernetes cluster), some optional parameters and a credential secret. To learn more about AppBinding and the problems it solves, please read this blog post: [The case for AppBinding](https://blog.byte.builders/post/the-case-for-appbinding). + +If you deploy a Vault using [KubeVault](https://kubevault.com/docs/latest/welcome/), the `AppBinding` object will be created automatically for it. Otherwise, you have to create an `AppBinding` object manually pointing to your desired Vault. + +KubeVault uses [Stash](https://stash.run/) to perform backup/recovery of Vault cluster. Stash needs to know how to connect with a target Vault and the credentials necessary to access it. This is done via an `AppBinding`. + +## AppBinding CRD Specification + +Like any official Kubernetes resource, an `AppBinding` has `TypeMeta`, `ObjectMeta` and `Spec` sections. However, unlike other Kubernetes resources, it does not have a `Status` section. + +An `AppBinding` object created by `KubeVault` for a Vault is shown below, + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault + namespace: demo +spec: + appRef: + apiGroup: kubevault.com + kind: VaultServer + name: vault + namespace: demo + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + backend: raft + backupTokenSecretRef: + name: vault-backup-token + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + stash: + addon: + backupTask: + name: vault-backup-1.10.3 + params: + - name: keyPrefix + value: k8s.75cf1449-0675-4cce-9fbe-965441450355.demo.vault + restoreTask: + name: vault-restore-1.10.3 + params: + - name: keyPrefix + value: k8s.75cf1449-0675-4cce-9fbe-965441450355.demo.vault + unsealer: + mode: + googleKmsGcs: + bucket: vault-testing-keys + credentialSecretRef: + name: gcp-cred + kmsCryptoKey: vault-testing-key + kmsKeyRing: vault-testing + kmsLocation: global + kmsProject: appscode-testing + secretShares: 5 + secretThreshold: 3 + vaultRole: vault-policy-controller +``` + +Here, we are going to describe the sections of an `AppBinding` crd. + +Here, we are going to describe the sections of an `AppBinding` crd that are relevant to KubeVault. + +### AppBinding `Spec` + +An `AppBinding` object has the following fields in the `spec` section: + +### spec.appRef + +`spec.appRef` refers to the application for which this AppBinding was created. + +```yaml +appRef: + apiGroup: kubevault.com + kind: VaultServer + name: vault + namespace: demo +``` + +#### spec.parameters.backupTokenSecretRef + +`spec.parameters.backupTokenSecretRef` specifies the name of the secret which contains the token with the permission to take backup snapshot & restore. This secret must be in the same namespace as the `AppBinding`. + +This secret must contain the following keys: + +| Key | Usage | +|:----------:|---------------------------------------------------------| +| `token` | token with permission to take backup snapshot & restore | + +### spec.parameters.backend + +`spec.parameters.backend` indicates the Storage Backend type Vault is using. + +### spec.parameters.stash + +`spec.parameters.stash` section contains the stash parameters for Backup & Restore tasks. `spec.parameters.stash.addon` contains the +information about the `Task` for backup & restore. It also contains the `params` which indicates the `keyPrefix` +that is prepended with the name of vault `unseal-keys` & `root-token`, +e.g. `k8s.kubevault.com.demo.vault-root-token`, `k8s.kubevault.com.demo.vault-root-token-unseal-key-0`, `k8s.kubevault.com.demo.vault-root-token-unseal-key-1`, etc. + +```yaml +stash: + addon: + backupTask: + name: vault-backup-1.10.3 + params: + - name: keyPrefix + value: k8s.kubevault.com.demo.vault + restoreTask: + name: vault-restore-1.10.3 + params: + - name: keyPrefix + value: k8s.kubevault.com.demo.vault +``` + +### spec.parameters.unsealer + +`spec.parameters.unsealer` contains the Vault unsealer information, e.g. secret shares & threshold of unseal keys, the location of unseal-keys, etc. + +```yaml +unsealer: + mode: + googleKmsGcs: + bucket: vault-testing-keys + credentialSecretRef: + name: gcp-cred + kmsCryptoKey: vault-testing-key + kmsKeyRing: vault-testing + kmsLocation: global + kmsProject: appscode-testing + secretShares: 5 + secretThreshold: 3 +``` + +### spec.clientConfig + +`spec.clientConfig` is a required field that specifies the information to make a connection with an app. + +```yaml +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: HTTPS + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9ERXlNamN3TkRVNU1qVmFGdzB5T0RFeU1qUXdORFU1TWpWYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMVhid2wyQ1NNc2VQTU5RRzhMd3dUVWVOCkI1T05oSTlDNzFtdUoyZEZjTTlUc1VDQnlRRk1weUc5dWFvV3J1ZDhtSWpwMVl3MmVIUW5udmoybXRmWGcrWFcKSThCYkJUaUFKMWxMMFE5MlV0a1BLczlXWEt6dTN0SjJUR1hRRDhhbHZhZ0JrR1ViOFJYaUNqK2pnc1p6TDRvQQpNRWszSU9jS0xnMm9ldFZNQ0hwNktpWTBnQkZiUWdJZ1A1TnFwbksrbU02ZTc1ZW5hWEdBK2V1d09FT0YwV0Z2CmxGQmgzSEY5QlBGdTJKbkZQUlpHVDJKajBRR1FNeUxodEY5Tk1pZTdkQnhiTWhRVitvUXp2d1EvaXk1Q2pndXQKeDc3d29HQ2JtM0o4cXRybUg2Tjl6Tlc3WlR0YTdLd05PTmFoSUFEMSsrQm5rc3JvYi9BYWRKT0tMN2dLYndJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFXeWFsdUt3Wk1COWtZOEU5WkdJcHJkZFQyZnFTd0lEOUQzVjN5anBlaDVCOUZHN1UKSS8wNmpuRVcyaWpESXNHNkFDZzJKOXdyaSttZ2VIa2Y2WFFNWjFwZHRWeDZLVWplWTVnZStzcGdCRTEyR2NPdwpxMUhJb0NrekVBMk5HOGRNRGM4dkQ5WHBQWGwxdW5veWN4Y0VMeFVRSC9PRlc4eHJxNU9vcXVYUkxMMnlKcXNGCmlvM2lJV3EvU09Yajc4MVp6MW5BV1JSNCtSYW1KWjlOcUNjb1Z3b3R6VzI1UWJKWWJ3QzJOSkNENEFwOUtXUjUKU2w2blk3NVMybEdSRENsQkNnN2VRdzcwU25seW5mb3RaTUpKdmFzbStrOWR3U0xtSDh2RDNMMGNGOW5SOENTSgpiTjBiZzczeVlWRHgyY3JRYk0zcko4dUJnY3BsWlRpUy91SXJ2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +``` + +It has the following fields: + +- `clientConfig.url` : `Optional`. Specifies the location of the app, in standard URL form (`[scheme://]host:port/path`). + +- `clientConfig.service`: `Optional`. Specifies the reference of the Kubernetes service for this app. It has the following fields: + + - `service.scheme` : `Optional`. Specifies which scheme to use, for example, HTTP, https. If specified, then it will be applied as the prefix in this format: `scheme://`. If not specified, then nothing will be prefixed. + - `service.name` : `Required`. Specifies the name of the service. This `service.name` and AppBinding's namespace will be used to create app DNS. + - `service.port` : `Required`. Specifies the port that will be exposed by this app. + - `service.path` : `Optional`. Specifies the URL path which will be sent in any request to this service. + - `service.query` : `Optional`. Specifies the encoded query string, without '?' which will be sent in any request to this service. + +> Note: Either `clientConfig.url` or `clientConfig.service` must be specified. + +- `clientConfig.caBundle`: `Optional`. Specifies the PEM encoded CA bundle which will be used to validate the serving certificate of this app. + +- `clientConfig.insecureSkipTLSVerify`: `Optional`. To skip TLS certificate verification when communicating with this app. This is strongly discouraged. You should use the `clientConfig.caBundle` instead. + +### spec.secret + +`spec.secret` is an optional field that specifies the name of the secret containing credentials associated with AppBinding. It must be in AppBinding's namespace. + +```yaml +spec: + secret: + name: vault-token +``` + +### spec.parameters + +`spce.parameters` is an optional field that specifies the list of parameters to be used to connect to the app, backup, restore, etc. The Parameters field is *not* secret or secured in any way and should *never* be used to hold sensitive information. + +```yaml +spec: + parameters: + apiVersion: config.kubevault.com/v1alpha1 + backend: raft + backupTokenSecretRef: + name: vault-backup-token + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + stash: + addon: + backupTask: + name: vault-backup-1.10.3 + params: + - name: keyPrefix + value: k8s.75cf1449-0675-4cce-9fbe-965441450355.demo.vault + restoreTask: + name: vault-restore-1.10.3 + params: + - name: keyPrefix + value: k8s.75cf1449-0675-4cce-9fbe-965441450355.demo.vault + unsealer: + mode: + googleKmsGcs: + bucket: vault-testing-keys + credentialSecretRef: + name: gcp-cred + kmsCryptoKey: vault-testing-key + kmsKeyRing: vault-testing + kmsLocation: global + kmsProject: appscode-testing + secretShares: 5 + secretThreshold: 3 + vaultRole: vault-policy-controller +``` + +### spec.secretTransforms + +`spec.secretTransforms` is an optional field that contains the list of transformations that should be applied to the credentials associated with the AppBinding before they are inserted into the Secret. For example, the credential secret specified in `spec.secret.name` has the key `USERNAME`, but the consumer requires the username to be exposed under the key `DB_USER` instead. To have the KubeVault operator transform the secret, the following secret transformation must be specified in `spec.secretTransforms`. + +```yaml +spec: + secretTransforms: + - renameKey: + from: USERNAME + to: DB_USER +``` + +It has the following fields: + +- `secretTransforms[].renameKey`: `Optional`. Specifies a transform that renames a credentials secret entry's key. It has the following fields: + - `renameKey.from`: `Required`. Specifies the name of the key to rename. + - `renameKey.to`: `Required`. Specifies the new name for the key. + +- `secretTransforms[].addKey`: `Optional`. Specifies a transform that adds an additional key to the credentials secret. + - `addKey.key`: `Required`. Specifies the name of the key to add. + - `addKey.value`: `Required`. Specifies the value (possibly non-binary) to add to the secret under the specified key. + - `addKey.stringValue`: `Required`. Specifies the string value to add to the secret under the specified key. If both `addKey.value` and `addKey.stringValue` are specified, then `addKey.value` is ignored and `addKey.stringValue` is stored. + - `addKey.jsonPathExpression`: `Required`. Specifies the JSONPath expression, the result of which will be added to the Secret under the specified key. For example, given the following credentials: `{ "foo": { "bar": "foobar" } }` and the jsonPathExpression `{.foo.bar}`, the value `foobar` will be stored in the credentials secret under the specified key. + +- `secretTransforms[].addKeysFrom`: `Optional`. Specifies a transform that merges all the entries of an existing secret into the credentials secret. + - `addKeysFrom.secretRef.name`: `Optinal`. Specifies the name of the secret. + - `addKeysFrom.secretRef.namespace`: `Optinal`. Specifies the namespace of the secret. + +- `secretTransforms[].removeKey`: `Optional`. Specifies a transform that removes a credentials secret entry. + - `removeKey.key`. `Required`. Specifies the key to remove from secret. + diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/_index.md b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/_index.md new file mode 100755 index 000000000..028963fcf --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/_index.md @@ -0,0 +1,17 @@ +--- +title: Vault Server Authentication +menu: + docs_v2025.11.21: + identifier: auth-methods-vault-server-crds + name: Authentication + parent: vault-server-crds-concepts + weight: 30 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding.md b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding.md new file mode 100644 index 000000000..14fb8cc87 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding.md @@ -0,0 +1,156 @@ +--- +title: AppBinding | KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: appbinding-auth-methods + name: AppBinding + parent: auth-methods-vault-server-crds + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# AppBinding + +## What is AppBinding + +AppBinding CRD provides a way to specify connection information, credential, and parameters that are necessary for communicating with an app/service. In KubeVault operator, AppBinding used to communicate with externally provisioned Vault, database, etc. + +An `AppBinding` is a Kubernetes `CustomResourceDefinition`(CRD) which points to an application using either its URL (usually for a non-Kubernetes resident service instance) or a Kubernetes service object (if self-hosted in a Kubernetes cluster), some optional parameters and a credential secret. To learn more about AppBinding and the problems it solves, please read this blog post: [The case for AppBinding](https://blog.byte.builders/post/the-case-for-appbinding). + +## AppBinding CRD Specification + +Like any official Kubernetes resource, an `AppBinding` has `TypeMeta`, `ObjectMeta` and `Spec` sections. However, unlike other Kubernetes resources, it does not have a `Status` section. + +An `AppBinding` object created by `KubeVault` for a Vault server is shown below, + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + type: vault + secret: + name: vault-token + clientConfig: + service: + name: vault + port: 8200 + scheme: HTTPS + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9ERXlNamN3TkRVNU1qVmFGdzB5T0RFeU1qUXdORFU1TWpWYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMVhid2wyQ1NNc2VQTU5RRzhMd3dUVWVOCkI1T05oSTlDNzFtdUoyZEZjTTlUc1VDQnlRRk1weUc5dWFvV3J1ZDhtSWpwMVl3MmVIUW5udmoybXRmWGcrWFcKSThCYkJUaUFKMWxMMFE5MlV0a1BLczlXWEt6dTN0SjJUR1hRRDhhbHZhZ0JrR1ViOFJYaUNqK2pnc1p6TDRvQQpNRWszSU9jS0xnMm9ldFZNQ0hwNktpWTBnQkZiUWdJZ1A1TnFwbksrbU02ZTc1ZW5hWEdBK2V1d09FT0YwV0Z2CmxGQmgzSEY5QlBGdTJKbkZQUlpHVDJKajBRR1FNeUxodEY5Tk1pZTdkQnhiTWhRVitvUXp2d1EvaXk1Q2pndXQKeDc3d29HQ2JtM0o4cXRybUg2Tjl6Tlc3WlR0YTdLd05PTmFoSUFEMSsrQm5rc3JvYi9BYWRKT0tMN2dLYndJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFXeWFsdUt3Wk1COWtZOEU5WkdJcHJkZFQyZnFTd0lEOUQzVjN5anBlaDVCOUZHN1UKSS8wNmpuRVcyaWpESXNHNkFDZzJKOXdyaSttZ2VIa2Y2WFFNWjFwZHRWeDZLVWplWTVnZStzcGdCRTEyR2NPdwpxMUhJb0NrekVBMk5HOGRNRGM4dkQ5WHBQWGwxdW5veWN4Y0VMeFVRSC9PRlc4eHJxNU9vcXVYUkxMMnlKcXNGCmlvM2lJV3EvU09Yajc4MVp6MW5BV1JSNCtSYW1KWjlOcUNjb1Z3b3R6VzI1UWJKWWJ3QzJOSkNENEFwOUtXUjUKU2w2blk3NVMybEdSRENsQkNnN2VRdzcwU25seW5mb3RaTUpKdmFzbStrOWR3U0xtSDh2RDNMMGNGOW5SOENTSgpiTjBiZzczeVlWRHgyY3JRYk0zcko4dUJnY3BsWlRpUy91SXJ2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +``` + +Here, we are going to describe the sections of an `AppBinding` crd that are relevant to KubeVault. + +### AppBinding `Spec` + +An `AppBinding` object has the following fields in the `spec` section: + +### spec.type + +`spec.type` is an optional field that specifies the type of app. + +```yaml +spec: + type: vault +``` + +### spec.clientConfig + +`spec.clientConfig` is a required field that specifies the information to make a connection with an app. + +```yaml +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: HTTPS + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9ERXlNamN3TkRVNU1qVmFGdzB5T0RFeU1qUXdORFU1TWpWYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMVhid2wyQ1NNc2VQTU5RRzhMd3dUVWVOCkI1T05oSTlDNzFtdUoyZEZjTTlUc1VDQnlRRk1weUc5dWFvV3J1ZDhtSWpwMVl3MmVIUW5udmoybXRmWGcrWFcKSThCYkJUaUFKMWxMMFE5MlV0a1BLczlXWEt6dTN0SjJUR1hRRDhhbHZhZ0JrR1ViOFJYaUNqK2pnc1p6TDRvQQpNRWszSU9jS0xnMm9ldFZNQ0hwNktpWTBnQkZiUWdJZ1A1TnFwbksrbU02ZTc1ZW5hWEdBK2V1d09FT0YwV0Z2CmxGQmgzSEY5QlBGdTJKbkZQUlpHVDJKajBRR1FNeUxodEY5Tk1pZTdkQnhiTWhRVitvUXp2d1EvaXk1Q2pndXQKeDc3d29HQ2JtM0o4cXRybUg2Tjl6Tlc3WlR0YTdLd05PTmFoSUFEMSsrQm5rc3JvYi9BYWRKT0tMN2dLYndJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFXeWFsdUt3Wk1COWtZOEU5WkdJcHJkZFQyZnFTd0lEOUQzVjN5anBlaDVCOUZHN1UKSS8wNmpuRVcyaWpESXNHNkFDZzJKOXdyaSttZ2VIa2Y2WFFNWjFwZHRWeDZLVWplWTVnZStzcGdCRTEyR2NPdwpxMUhJb0NrekVBMk5HOGRNRGM4dkQ5WHBQWGwxdW5veWN4Y0VMeFVRSC9PRlc4eHJxNU9vcXVYUkxMMnlKcXNGCmlvM2lJV3EvU09Yajc4MVp6MW5BV1JSNCtSYW1KWjlOcUNjb1Z3b3R6VzI1UWJKWWJ3QzJOSkNENEFwOUtXUjUKU2w2blk3NVMybEdSRENsQkNnN2VRdzcwU25seW5mb3RaTUpKdmFzbStrOWR3U0xtSDh2RDNMMGNGOW5SOENTSgpiTjBiZzczeVlWRHgyY3JRYk0zcko4dUJnY3BsWlRpUy91SXJ2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +``` + +It has following fields: + +- `clientConfig.url` : `Optional`. Specifies the location of the app, in standard URL form (`[scheme://]host:port/path`). + +- `clientConfig.service`: `Optional`. Specifies the reference of the Kubernetes service for this app. It has the following fields: + + - `service.scheme` : `Optional`. Specifies which scheme to use, for example, HTTP, https. If specified, then it will be applied as the prefix in this format: `scheme://`. If not specified, then nothing will be prefixed. + - `service.name` : `Required`. Specifies the name of the service. This `service.name` and AppBinding's namespace will be used to create app DNS. + - `service.port` : `Required`. Specifies the port that will be exposed by this app. + - `service.path` : `Optional`. Specifies the URL path which will be sent in any request to this service. + - `service.query` : `Optional`. Specifies the encoded query string, without '?' which will be sent in any request to this service. + +> Note: Either `clientConfig.url` or `clientConfig.service` must be specified. + +- `clientConfig.caBundle`: `Optional`. Specifies the PEM encoded CA bundle which will be used to validate the serving certificate of this app. + +- `clientConfig.insecureSkipTLSVerify`: `Optional`. To skip TLS certificate verification when communicating with this app. This is strongly discouraged. You should use the `clientConfig.caBundle` instead. + +### spec.secret + +`spec.secret` is an optional field that specifies the name of the secret containing credentials associated with AppBinding. It must be in AppBinding's namespace. + +```yaml +spec: + secret: + name: vault-token +``` + +### spec.parameters + +`spce.parameters` is an optional field that specifies the list of parameters to be used to connect to the app. The Parameters field is *not* secret or secured in any way and should *never* be used to hold sensitive information. + +```yaml +spec: + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: kubernetes + vaultRole: vault-policy-controller + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true +``` + +### spec.secretTransforms + +`spec.secretTransforms` is an optional field that contains the list of transformations that should be applied to the credentials associated with the AppBinding before they are inserted into the Secret. For example, the credential secret specified in `spec.secret.name` has the key `USERNAME`, but the consumer requires the username to be exposed under the key `DB_USER` instead. To have the KubeVault operator transform the secret, the following secret transformation must be specified in `spec.secretTransforms`. + +```yaml +spec: + secretTransforms: + - renameKey: + from: USERNAME + to: DB_USER +``` + +It has the following fields: + +- `secretTransforms[].renameKey`: `Optional`. Specifies a transform that renames a credentials secret entry's key. It has the following fields: + - `renameKey.from`: `Required`. Specifies the name of the key to rename. + - `renameKey.to`: `Required`. Specifies the new name for the key. + +- `secretTransforms[].addKey`: `Optional`. Specifies a transform that adds an additional key to the credentials secret. + - `addKey.key`: `Required`. Specifies the name of the key to add. + - `addKey.value`: `Required`. Specifies the value (possibly non-binary) to add to the secret under the specified key. + - `addKey.stringValue`: `Required`. Specifies the string value to add to the secret under the specified key. If both `addKey.value` and `addKey.stringValue` are specified, then `addKey.value` is ignored and `addKey.stringValue` is stored. + - `addKey.jsonPathExpression`: `Required`. Specifies the JSONPath expression, the result of which will be added to the Secret under the specified key. For example, given the following credentials: `{ "foo": { "bar": "foobar" } }` and the jsonPathExpression `{.foo.bar}`, the value `foobar` will be stored in the credentials secret under the specified key. + +- `secretTransforms[].addKeysFrom`: `Optional`. Specifies a transform that merges all the entries of an existing secret into the credentials secret. + - `addKeysFrom.secretRef.name`: `Optinal`. Specifies the name of the secret. + - `addKeysFrom.secretRef.namespace`: `Optinal`. Specifies the namespace of the secret. + +- `secretTransforms[].removeKey`: `Optional`. Specifies a transform that removes a credentials secret entry. + - `removeKey.key`. `Required`. Specifies the key to remove from secret. diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/aws-iam.md b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/aws-iam.md new file mode 100644 index 000000000..d42302be0 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/aws-iam.md @@ -0,0 +1,89 @@ +--- +title: Connect to Vault using AWS IAM Auth Method +menu: + docs_v2025.11.21: + identifier: aws-iam-auth-methods + name: AWS IAM + parent: auth-methods-vault-server-crds + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Connect to Vault using AWS IAM Auth Method + +The KubeVault operator uses an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) to connect to an externally provisioned Vault server. For [AWS IAM authentication](https://www.vaultproject.io/docs/auth/aws.html#iam-auth-method), it has to be enabled and configured in the Vault server. Follow the steps below to create an appropriate AppBinding: + +- You have to specify `spec.secret` in the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding). + +- The specified secret must be in AppBinding's namespace. + +- The type of the specified secret must be `"kubevault.com/aws"`. + +- The specified secret data can have the following key: + - `Secret.Data["access_key_id"]` : `Required`. Specifies AWS access key. + - `Secret.Data["secret_access_key"]` : `Required`. Specifies AWS access secret. + - `Secret.Data["security_token"]` : `Optional`. Specifies AWS security token. + +- The additional information required for AWS IAM authentication can be provided as AppBinding's `spec.parameters`. + + ```yaml + spec: + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: my-aws + vaultRole: demo + aws: + headerValue: vault.example.com + ``` + + - `parameters.path` : `optional`. Specifies the path where AWS auth is enabled in Vault. Default to `aws`. + - `parameters.vaultRole` : `required`. Specifies the name of the Vault auth [role](https://www.vaultproject.io/api/auth/aws/index.html#create-role) against which login will be performed. + - `parameters.aws.headerValue` : `optional`. Specifies the header value that required if X-Vault-AWS-IAM-Server-ID Header is set in Vault. + +Sample AppBinding and Secret is given below: + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + secret: + name: aws-cred + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: my-aws + vaultRole: demo + aws: + headerValue: vault.example.com + clientConfig: + service: + name: vault + scheme: HTTPS + port: 8200 + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9ERXlNamN3TkRVNU1qVmFGdzB5T0RFeU1qUXdORFU1TWpWYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMVhid2wyQ1NNc2VQTU5RRzhMd3dUVWVOCkI1T05oSTlDNzFtdUoyZEZjTTlUc1VDQnlRRk1weUc5dWFvV3J1ZDhtSWpwMVl3MmVIUW5udmoybXRmWGcrWFcKSThCYkJUaUFKMWxMMFE5MlV0a1BLczlXWEt6dTN0SjJUR1hRRDhhbHZhZ0JrR1ViOFJYaUNqK2pnc1p6TDRvQQpNRWszSU9jS0xnMm9ldFZNQ0hwNktpWTBnQkZiUWdJZ1A1TnFwbksrbU02ZTc1ZW5hWEdBK2V1d09FT0YwV0Z2CmxGQmgzSEY5QlBGdTJKbkZQUlpHVDJKajBRR1FNeUxodEY5Tk1pZTdkQnhiTWhRVitvUXp2d1EvaXk1Q2pndXQKeDc3d29HQ2JtM0o4cXRybUg2Tjl6Tlc3WlR0YTdLd05PTmFoSUFEMSsrQm5rc3JvYi9BYWRKT0tMN2dLYndJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFXeWFsdUt3Wk1COWtZOEU5WkdJcHJkZFQyZnFTd0lEOUQzVjN5anBlaDVCOUZHN1UKSS8wNmpuRVcyaWpESXNHNkFDZzJKOXdyaSttZ2VIa2Y2WFFNWjFwZHRWeDZLVWplWTVnZStzcGdCRTEyR2NPdwpxMUhJb0NrekVBMk5HOGRNRGM4dkQ5WHBQWGwxdW5veWN4Y0VMeFVRSC9PRlc4eHJxNU9vcXVYUkxMMnlKcXNGCmlvM2lJV3EvU09Yajc4MVp6MW5BV1JSNCtSYW1KWjlOcUNjb1Z3b3R6VzI1UWJKWWJ3QzJOSkNENEFwOUtXUjUKU2w2blk3NVMybEdSRENsQkNnN2VRdzcwU25seW5mb3RaTUpKdmFzbStrOWR3U0xtSDh2RDNMMGNGOW5SOENTSgpiTjBiZzczeVlWRHgyY3JRYk0zcko4dUJnY3BsWlRpUy91SXJ2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +``` + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: aws-cred + namespace: demo +type: kubevault.com/aws +data: + access_key_id: cm9vdA== + secret_access_key: cm9vdA== +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/azure.md b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/azure.md new file mode 100644 index 000000000..d542e7c6c --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/azure.md @@ -0,0 +1,95 @@ +--- +title: Connect to Vault using Azure Auth Method +menu: + docs_v2025.11.21: + identifier: azure-auth-methods + name: Azure + parent: auth-methods-vault-server-crds + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Connect to Vault using Azure Auth Method + +The KubeVault operator uses an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) to connect to an externally provisioned Vault server. For [Azure authentication](https://www.vaultproject.io/docs/auth/azure.html), it has to be [enabled](https://www.vaultproject.io/docs/auth/azure.html#via-the-cli-1) and [configured](https://www.vaultproject.io/docs/auth/azure.html#via-the-cli-1) in the Vault server. Follow the steps below to create an appropriate AppBinding: + +- You have to specify the k8s secret name in `spec.secret` in the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding). + +- The specified secret must be in AppBinding's namespace. + +- The type of the specified secret must be `"kubevault.com/azure"`. + +- The specified secret data can have the following key: + - `Secret.Data["msiToken"]` : `Required`. Signed JSON Web Token (JWT) from Azure MSI. Documentation can be found in [here](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) + +- The additional information required for the Azure authentication method can be provided as AppBinding's `spec.parameters`. + + ```yaml + spec: + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: my-azure + vaultRole: demo-role + azure: + subscriptionID: 1bfc9f66-316d-433e-b13d-c55589f642ca + resourceGroupName: vault-test + vmName: test + vmssName: test-set + ``` + + - `path` : `optional`. Specifies the path where Azure auth is enabled in Vault. If this path is not provided, the path will be set by default path `azure`. + - `vaultRole` : `required`. Specifies the name of the Vault auth [role](https://www.vaultproject.io/api/auth/azure/index.html#create-role) against which login will be performed. + - `azure.subscriptionID` : `optional`. Specifies the subscription ID for the machine that generated the MSI token. This information can be obtained through instance metadata. + - `azure.resourceGroupName` : `optional`. Specifies the resource group for the machine that generated the MSI token. This information can be obtained through instance metadata. + - `azure.vmName` : `optional`. Specifies the virtual machine name for the machine that generated the MSI token. This information can be obtained through instance metadata. If `vmssName` is provided, this value is ignored. + - `azure.vmssName` : `optional`. Specifies the virtual machine scale set name for the machine that generated the MSI token. This information can be obtained through instance metadata. + +Sample AppBinding and Secret is given below: + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + secret: + name: azure-cred + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: my-azure + vaultRole: demo-role + azure: + subscriptionID: 1bfc9f66-316d-433e-b13d-c55589f642ca + resourceGroupName: vault-test + vmName: test + vmssName: test-set + clientConfig: + service: + name: vault + scheme: HTTPS + port: 8200 + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9UQTFNREl3T1RNeU5UaGFGdzB5T1RBME1qa3dPVE15TlRoYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdkVwTGVUT05ZRGxuTDkyMDlVQWY0Njc1CnR4MXpGL2J2UlZkejZjcVlYYWI1d0o0TmJoNGUxRFJDbmp6WXg1aDd0N1RLQXpvN3BWMWlzOFVHTTJUWGdPcloKa0hLQVJjOEFjekgxekE5Sk9mWkdGVk4xaXZBOTJHZ0xvVHNURDh4VTk0OWZ3Um8rYm5RemFqL2tLeHA5Z0puZQppYzBUenV5SEw2UTVseXRTVkoxWWhHSGdBdGM0eTBOcGZXZTZRekk1RnFXM2t1THFyaEVmRGV5TnR0UDUzaVV4ClpJN1IrbHBlVWsrY0NKZ2U0cTU1eGUvVmFpdEN6VVFIQVhLd0czRlNoYTc5cTBtb3J3N0ZIMW5YRDQwa0EwUXkKRlUxQTZtaDd5QVovb3BydWF0NFZjSDNwakdweGFvMzdLMGZQOXZXVjBvUnI5bm85YnM1MlI5L0I4cTVwYndJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFsd09iT3luNzZNMFRYMm53d1hlUkRreVdmNVczT3U4WGJQS3FEeXF1VnBIVUY2dHMKMmhuZFcyTXFJTEx3OUFYOXp1cFV4bzVKNEZadVNYYkNXUEt1a3VJbGtKYTRWMzAyeEtLNUJnT0R0TkdlQmNJQwpqNkFxZzUrU3dBVm9Va1FzcG52KzFBYVBOM0V1MldGNXlKaElaN0FnbjZERUYyWGlUQ3UvNm5lZVFLWC85QXVpCnNyTEZ2eE9TMEZuUTZ5YnpURGordHdTSGM4TkpHbWhKaGVOTVg5MmlYbHkrWG5VSmdRYU1tQzg5Y3JaRGRXczQKTnoyY0hMZFNZNnFNaHlSZGJ6NHZqdzlnVllMYXN5WjVFSTh2K1FmRTNOVE5SdlVJdlNwTVNQN09DT09UbTlteAprSlRVYjdCeW9DV0tzUDBGeWQ5RkdSVnZRQ0xFZi85MVNOeU5Sdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +``` + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: azure-cred + namespace: demo +type: kubevault.com/azure +data: + msiToken: ZXlKMGVYQWlPaUcFpDSTZJa2hDQ0o5LmV5SmhkV1FpT2lKpPaTh2YzNSekxuZHBibVJ2ZDNNdWJtVjBM +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/gcp-iam.md b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/gcp-iam.md new file mode 100644 index 000000000..fb3637a7e --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/gcp-iam.md @@ -0,0 +1,81 @@ +--- +title: Connect to Vault using GCP IAM Auth Method +menu: + docs_v2025.11.21: + identifier: gcp-iam-auth-methods + name: GCP IAM + parent: auth-methods-vault-server-crds + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Connect to Vault using GCP IAM Auth Method + +The KubeVault operator uses an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) to connect to an externally provisioned Vault server. For [GCP IAM authentication](https://www.vaultproject.io/docs/auth/gcp.html#configuration), it has to be enabled and configured in the Vault server. Follow the steps below to create an appropriate AppBinding: + +- You have to specify `spec.secret` in the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding). + +- The specified secret must be in AppBinding's namespace. + +- The type of the specified secret must be `"kubevault.com/gcp"`. + +- The specified secret data can have the following key: + - `Secret.Data["sa.json"]` : `Required`. Specifies the google application credentials. + +- The additional information required for the GCP IAM authentication method can be provided as AppBinding's `spec.parameters`. + + ```yaml + spec: + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: my-gcp + vaultRole: demo-role + ``` + + - `path` : `optional`. Specifies the path where GCP auth is enabled in Vault. If this path is not provided, the path will be set by default path `gcp`. + - `vaultRole` : `required`. Specifies the name of the Vault auth [role](https://www.vaultproject.io/api/auth/gcp/index.html#create-role) against which login will be performed. + +Sample AppBinding and Secret is given below: + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + secret: + name: gcp-cred + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: my-gcp + vaultRole: demo-role + clientConfig: + service: + name: vault + scheme: HTTPS + port: 8200 + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9UQTBNVGN3TkRFM05UVmFGdzB5T1RBME1UUXdOREUzTlRWYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBNGxKeTNsMThKMjZ2WWlZakNYZm54M1dvCnpaNUh4WUUvWmVNT1BKTFZyN0kwb2Rrc3N6bXhieWROaGJaN2kvQ2xOUzRvclB1eVFJZ29Ncng1bHRvTDhEd1cKRmZQZ0RGbFM4WjArcHNwRU00WEtVYnpBQk9lY0JaUnhZYTJPdmJqeFZjTE1PYzI5VGw4TzYzc2ZFeTlDcWhrRApEaUZDeFQ2bFd1MjZ0YmNzZEwwNFdBVzZDN1pyakhtaUMvWHhGcnl6STllRUVhb0xkVTdHMDJhTmFmOVBZM0RaCjBNRTJtOUNXMDYzOFZMeCtZMjR3cXMrQVJrUmg3cUVVKy9qK2lId2Y5N0hKMi8vcGdNMEFRcklOSk1kQ1ZNZEsKZ2hGYUs4NjZBdDNsa1R0U0FOclVtM3pCN1lEN20rYjNTRlJ5clMzM2RDZG5zNlp3NDdTQjFjWEJxcCs1SFFJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFXeUZTR1drSkV3U25nTW5zQXJ3c2xYckIyQm1NNHdNdzJtSkwyWk9CSDVlWm9ka0QKVmpsS1ltSVlKRE9rS2pIR2JuQys3KzVJd1J0ais4Um9uT0lSSnp3Vy9PZnUyUFJML1JmQmxmVmwxKzJJZlNWVQprbEVsRnlHNHRQL202ZjhWU2U5ZEpSZkFOWGRkcGdlOUd3dFlTbGsyaGI1aE5RTzVFSTAyVVYwdVVpWGcwNWRECkgyYkppQ1FQcHBxc3NiL09yNWQ5YXBSV3FMMzliQ0Z5Zi9GTzhZVVNYL0NEM1ZlZzhic24yWWc2bU14b2tUTGIKM1EvWll0NGthS0t0UVNreDV3NXh6bmZGNVBHenRIVmtSMkc0SVNRdDBVK2t1TVpRZTEyVCszS2ZqVitSVkZkZApWRkFpekxPOC82ZEFvRk5mQ3M4c2xsUDVEYXRLWnNXT2hROFJMZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +``` + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: gcp-cred + namespace: demo +type: kubevault.com/gcp +data: + sa.json: ZXlKMGVYQWlPaUcFpDSTZJa2hDQ0o5LmV5SmhkV1FpT2lKpPaTh2YzNSekxuZHBibVJ2ZDNNdWJtVjBM +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/jwt-oidc.md b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/jwt-oidc.md new file mode 100644 index 000000000..8df11c7b7 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/jwt-oidc.md @@ -0,0 +1,97 @@ +--- +title: Connect to Vault using JWT/OIDC Auth Method +menu: + docs_v2025.11.21: + identifier: jwt-oidc-auth-methods + name: JWT/OIDC + parent: auth-methods-vault-server-crds + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +The `JWT` auth method can be used to authenticate with Vault using `OIDC` or by providing a `JWT`. + +The `OIDC` method allows authentication via a configured `OIDC Provider` using the user's web browser. This method may be initiated from the `Vault UI` or the command line. Alternatively, a `JWT` can be provided directly. + +## Enable & Configure JWT/OIDC Auth method + +While deploying the `VaultServer` it's possible to define the list of auth methods users want to enable with it. + +A `VaultServer` `.spec.authMethods` section may look like this: + +```yaml +spec: + authMethods: + - type: jwt + path: jwt + jwtConfig: + ... + - type: oidc + path: oidc + oidcConfig: + ... + +``` + +* `.spec.authMethods.type` is a required field, the type of authentication method we want to enable. +* `.spec.authMethods.path` is a required field, the path where we want to enable this authentication method. +* `.spec.authMethods.jwtConfig / .spec.authMethods.oidcConfig` contains various configuration for this authentication method. Some of the `paramerters` are listed here: + * `defaultLeaseTTL` - The default lease duration, specified as a string duration like "5s" or "30m". + * `maxLeaseTTL` - The maximum lease duration, specified as a string duration like "5s" or "30m". + * `pluginName` - The name of the plugin in the plugin catalog to use. + * `auditNonHMACRequestKeys` - List of keys that will not be HMAC'd by audit devices in the request data object. + * `auditNonHMACResponseKeys` - List of keys that will not be HMAC'd by audit devices in the response data object. + * `listingVisibility` - Specifies whether to show this mount in the UI-specific listing endpoint. + * `passthroughRequestHeaders` - List of headers to whitelist and pass from the request to the backend. + * `credentialSecretRef` - K8s Secret reference containing credential related secrets. + * `tlsSecretRef` - K8s Secret reference containing tls related secrets. + * `oidcDiscoveryURL` - The OIDC Discovery URL, without any .well-known component (base path). Cannot be used with "jwks_url" or "jwt_validation_pubkeys". + * `oidcClientID` - The OAuth Client ID from the provider for OIDC roles. + * `oidcResponseMode` - The response mode to be used in the OAuth2 request. Allowed values are "query" and "form_post". Defaults to "query". If using Vault namespaces, and oidc_response_mode is "form_post", then "namespace_in_state" should be set to false. + * `oidcResponseTypes` - (comma-separated string, or array of strings: ) - The response types to request. Allowed values are "code" and "id_token". Defaults to "code". Note: "id_token" may only be used if "oidc_response_mode" is set to "form_post". + * `defaultRole` - The default role to use if none is provided during login. + * `providerConfig` - Configuration options for provider-specific handling. Providers with specific handling include: Azure, Google. The options are described in each provider's section in OIDC Provider Setup. + * `jwksURL` - JWKS URL to use to authenticate signatures. Cannot be used with "oidc_discovery_url" or "jwt_validation_pubkeys". + * `jwtValidationPubkeys` - (comma-separated string, or array of strings: ). A list of PEM-encoded public keys to use to authenticate signatures locally. Cannot be used with "jwks_url" or "oidc_discovery_url". + * `jwtSupportedAlgs` - (comma-separated string, or array of strings: ) A list of supported signing algorithms. Defaults to [RS256] for OIDC roles. Defaults to all available algorithms for JWT roles. + * `boundIssuer` - The value against which to match the iss claim in a JWT. + +After an authentication method is successfully enabled, `KubeVault` operator will configure it with the provided configuration. + +After successfully enabling & configuring authentication methods, a VaultServer `.status.authMethodStatus` may look like this: +```yaml +status: + authMethodStatus: + - path: jwt + status: EnableSucceeded + type: jwt + - path: kubernetes + status: EnableSucceeded + type: kubernetes + +``` + +We can verify it using the `Vault CLI`: + +```bash +$ vault auth list + +Path Type Accessor Description +---- ---- -------- ----------- +jwt/ jwt auth_jwt_ba23cc30 n/a +kubernetes/ kubernetes auth_kubernetes_40fd86fd n/a +token/ token auth_token_950c8b80 token based credentials +``` + +So, this is how `JWT/OIDC` authentication method could be enabled & configured with `KubeVault`. + +> For a step-by-step guide on JWT/OIDC authentication method, see [this](/docs/v2025.11.21/guides/vault-server/auth-method). diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/kubernetes.md b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/kubernetes.md new file mode 100644 index 000000000..e2a0d6d3d --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/kubernetes.md @@ -0,0 +1,149 @@ +--- +title: Connect to Vault using Kubernetes Auth Method +menu: + docs_v2025.11.21: + identifier: kubernetes-auth-methods + name: Kubernetes + parent: auth-methods-vault-server-crds + weight: 20 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Connect to Vault using Kubernetes Auth Method + +The KubeVault operator uses an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) to connect to an externally provisioned Vault server. For [Kubernetes Authentication](https://www.vaultproject.io/docs/auth/kubernetes.html), it has to be enabled and configured in the Vault server. In KubeVault operator, it can be performed in two ways: + +- Using ServiceAccount Name +- Using ServiceAccount Token Secret + +## Kubernetes Authentication using ServiceAccount Name + +To perform Kubernetes Authentication using ServiceAccount Name, + +- You have to specify serviceaccount name and [role](https://www.vaultproject.io/api/auth/kubernetes/index.html#create-role) name in `spec.parameters` of the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding). If Kubernetes auth method is enabled in different path (not `kubernetes`), then you also have to specify it in `spec.parameters` of AppBinding. + + ```yaml + spec: + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: k8s # Kubernetes auth is enabled in this path + vaultRole: demo # role name against which login will be done + kubernetes: + serviceAccountName: vault-sa # service account name + ``` + +- The specified ServiceAccount must be in AppBinding's namespace. + +Sample AppBinding is given below: + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: k8s + vaultRole: demo + kubernetes: + serviceAccountName: vault-sa + clientConfig: + service: + name: vault + scheme: HTTPS + port: 8200 + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9ERXlNamN3TkRVNU1qVmFGdzB5T0RFeU1qUXdORFU1TWpWYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMVhid2wyQ1NNc2VQTU5RRzhMd3dUVWVOCkI1T05oSTlDNzFtdUoyZEZjTTlUc1VDQnlRRk1weUc5dWFvV3J1ZDhtSWpwMVl3MmVIUW5udmoybXRmWGcrWFcKSThCYkJUaUFKMWxMMFE5MlV0a1BLczlXWEt6dTN0SjJUR1hRRDhhbHZhZ0JrR1ViOFJYaUNqK2pnc1p6TDRvQQpNRWszSU9jS0xnMm9ldFZNQ0hwNktpWTBnQkZiUWdJZ1A1TnFwbksrbU02ZTc1ZW5hWEdBK2V1d09FT0YwV0Z2CmxGQmgzSEY5QlBGdTJKbkZQUlpHVDJKajBRR1FNeUxodEY5Tk1pZTdkQnhiTWhRVitvUXp2d1EvaXk1Q2pndXQKeDc3d29HQ2JtM0o4cXRybUg2Tjl6Tlc3WlR0YTdLd05PTmFoSUFEMSsrQm5rc3JvYi9BYWRKT0tMN2dLYndJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFXeWFsdUt3Wk1COWtZOEU5WkdJcHJkZFQyZnFTd0lEOUQzVjN5anBlaDVCOUZHN1UKSS8wNmpuRVcyaWpESXNHNkFDZzJKOXdyaSttZ2VIa2Y2WFFNWjFwZHRWeDZLVWplWTVnZStzcGdCRTEyR2NPdwpxMUhJb0NrekVBMk5HOGRNRGM4dkQ5WHBQWGwxdW5veWN4Y0VMeFVRSC9PRlc4eHJxNU9vcXVYUkxMMnlKcXNGCmlvM2lJV3EvU09Yajc4MVp6MW5BV1JSNCtSYW1KWjlOcUNjb1Z3b3R6VzI1UWJKWWJ3QzJOSkNENEFwOUtXUjUKU2w2blk3NVMybEdSRENsQkNnN2VRdzcwU25seW5mb3RaTUpKdmFzbStrOWR3U0xtSDh2RDNMMGNGOW5SOENTSgpiTjBiZzczeVlWRHgyY3JRYk0zcko4dUJnY3BsWlRpUy91SXJ2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +``` + +## Kubernetes Authentication using ServiceAccount Token Secret + +To perform Kubernetes Authentication using ServiceAccount Token Secret, + +- You have to specify serviceaccount token secret in `spec.secret` of the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding). Kubernetes create a token secret for every serviceaccount. You can use that in `spec.secret`. + + ```bash + $ kubectl create serviceaccount sa + serviceaccount/sa created + + $ kubectl get serviceaccount/sa -o yaml + apiVersion: v1 + kind: ServiceAccount + metadata: + name: sa + namespace: default + secrets: + - name: sa-token-6n9pv + + $ kubectl get secrets/sa-token-6n9pv -o yaml + apiVersion: v1 + data: + ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t + namespace: ZGVmYXVsdA== + token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklpSjkuZXlK + kind: Secret + metadata: + annotations: + kubernetes.io/service-account.name: sa + kubernetes.io/service-account.uid: db22a517-0771-11e9-8744-080027907e77 + name: sa-token-6n9pv + namespace: default + type: kubernetes.io/service-account-token + ``` + +- The specified secret must be in AppBinding's namespace. + +- The specified token secret must have the following key: + - `Secret.Data["token"]` : `Required`. Specifies the serviceaccount token. + +- The type of the specified token secret must be `kubernetes.io/service-account-token`. + +- The additional information required for the Kubernetes authentication method can be provided as AppBinding's `spec.parameters`. + + ```yaml + spec: + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: k8s + vaultRole: demo-role + ``` + + - `path` : `optional`. Specifies the path where Kubernetes auth is enabled in Vault. If this path is not provided, the path will be set by default path `kubernetes`. + - `vaultRole` : `required`. Specifies the name of the Vault auth [role](https://www.vaultproject.io/api/auth/kubernetes/index.html#create-role) against which login will be performed. + +Sample AppBinding is given below: + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + secret: + name: sa-token + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: k8s + vaultRole: demo-role + clientConfig: + service: + name: vault + scheme: HTTPS + port: 8200 + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9ERXlNamN3TkRVNU1qVmFGdzB5T0RFeU1qUXdORFU1TWpWYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMVhid2wyQ1NNc2VQTU5RRzhMd3dUVWVOCkI1T05oSTlDNzFtdUoyZEZjTTlUc1VDQnlRRk1weUc5dWFvV3J1ZDhtSWpwMVl3MmVIUW5udmoybXRmWGcrWFcKSThCYkJUaUFKMWxMMFE5MlV0a1BLczlXWEt6dTN0SjJUR1hRRDhhbHZhZ0JrR1ViOFJYaUNqK2pnc1p6TDRvQQpNRWszSU9jS0xnMm9ldFZNQ0hwNktpWTBnQkZiUWdJZ1A1TnFwbksrbU02ZTc1ZW5hWEdBK2V1d09FT0YwV0Z2CmxGQmgzSEY5QlBGdTJKbkZQUlpHVDJKajBRR1FNeUxodEY5Tk1pZTdkQnhiTWhRVitvUXp2d1EvaXk1Q2pndXQKeDc3d29HQ2JtM0o4cXRybUg2Tjl6Tlc3WlR0YTdLd05PTmFoSUFEMSsrQm5rc3JvYi9BYWRKT0tMN2dLYndJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFXeWFsdUt3Wk1COWtZOEU5WkdJcHJkZFQyZnFTd0lEOUQzVjN5anBlaDVCOUZHN1UKSS8wNmpuRVcyaWpESXNHNkFDZzJKOXdyaSttZ2VIa2Y2WFFNWjFwZHRWeDZLVWplWTVnZStzcGdCRTEyR2NPdwpxMUhJb0NrekVBMk5HOGRNRGM4dkQ5WHBQWGwxdW5veWN4Y0VMeFVRSC9PRlc4eHJxNU9vcXVYUkxMMnlKcXNGCmlvM2lJV3EvU09Yajc4MVp6MW5BV1JSNCtSYW1KWjlOcUNjb1Z3b3R6VzI1UWJKWWJ3QzJOSkNENEFwOUtXUjUKU2w2blk3NVMybEdSRENsQkNnN2VRdzcwU25seW5mb3RaTUpKdmFzbStrOWR3U0xtSDh2RDNMMGNGOW5SOENTSgpiTjBiZzczeVlWRHgyY3JRYk0zcko4dUJnY3BsWlRpUy91SXJ2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/overview.md b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/overview.md new file mode 100644 index 000000000..ac19177d1 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/overview.md @@ -0,0 +1,34 @@ +--- +title: Managing Externally Provisioned Vault Servers +menu: + docs_v2025.11.21: + identifier: overview-auth-methods + name: External Vault + parent: auth-methods-vault-server-crds + weight: 5 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Managing Externally Provisioned Vault Servers + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. These Vault servers can be running outside a Kubernetes cluster or running inside a Kubernetes cluster but provisioned using a Helm chart. + +The KubeVault operator uses an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) to connect to an externally provisioned Vault server. Following authentication methods are currently supported by the KubeVault operator: + +- [AWS IAM Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/aws-iam) +- [Kubernetes Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/kubernetes) +- [TLS Certificates Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/tls) +- [Token Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/token) +- [Userpass Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/userpass) +- [GCP IAM Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/gcp-iam) +- [Azure Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/azure) +- [JWT/OIDC Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/jwt-oidc) diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/tls.md b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/tls.md new file mode 100644 index 000000000..52ebdbabf --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/tls.md @@ -0,0 +1,83 @@ +--- +title: Connect to Vault using TLS Certificate Auth Method +menu: + docs_v2025.11.21: + identifier: tls-auth-methods + name: TLS Certificates + parent: auth-methods-vault-server-crds + weight: 25 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Connect to Vault using TLS Certificate Auth Method + +The KubeVault operator uses an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) to connect to an externally provisioned Vault server. For [TLS Certificates authentication](https://www.vaultproject.io/docs/auth/cert.html), it has to be enabled and configured in Vault. Follow the steps below to create an appropriate AppBinding: + +- You have to specify `spec.secret` in the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding). + +- The specified secret must be in AppBinding's namespace. + +- The type of the specified secret must be `kubernetes.io/tls`. + +- The specified secret data must have the following key: + - `Secret.Data["tls.crt"]` : `Required`. Specifies the tls certificate. + - `Secret.Data["tls.key"]` : `Required`. Specifies the tls private key. + +- The additional information required for the TLS Certificate authentication method can be provided as AppBinding's `spec.parameters`. + + ```yaml + spec: + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: my-cert + vaultRole: demo-role + ``` + + - `path` : `optional`. Specifies the path where the TLS Certificate auth is enabled in Vault. If this path is not provided, the path will be set by default path `cert`. + - `vaultRole` : `required`. Specifies the name of the Vault auth [role](https://www.vaultproject.io/api/auth/cert/index.html#create-ca-certificate-role) against which login will be performed. + +Sample AppBinding and Secret is given below: + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + secret: + name: tls + clientConfig: + service: + name: vault + scheme: HTTPS + port: 8200 + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9ERXlNamN3TkRVNU1qVmFGdzB5T0RFeU1qUXdORFU1TWpWYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMVhid2wyQ1NNc2VQTU5RRzhMd3dUVWVOCkI1T05oSTlDNzFtdUoyZEZjTTlUc1VDQnlRRk1weUc5dWFvV3J1ZDhtSWpwMVl3MmVIUW5udmoybXRmWGcrWFcKSThCYkJUaUFKMWxMMFE5MlV0a1BLczlXWEt6dTN0SjJUR1hRRDhhbHZhZ0JrR1ViOFJYaUNqK2pnc1p6TDRvQQpNRWszSU9jS0xnMm9ldFZNQ0hwNktpWTBnQkZiUWdJZ1A1TnFwbksrbU02ZTc1ZW5hWEdBK2V1d09FT0YwV0Z2CmxGQmgzSEY5QlBGdTJKbkZQUlpHVDJKajBRR1FNeUxodEY5Tk1pZTdkQnhiTWhRVitvUXp2d1EvaXk1Q2pndXQKeDc3d29HQ2JtM0o4cXRybUg2Tjl6Tlc3WlR0YTdLd05PTmFoSUFEMSsrQm5rc3JvYi9BYWRKT0tMN2dLYndJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFXeWFsdUt3Wk1COWtZOEU5WkdJcHJkZFQyZnFTd0lEOUQzVjN5anBlaDVCOUZHN1UKSS8wNmpuRVcyaWpESXNHNkFDZzJKOXdyaSttZ2VIa2Y2WFFNWjFwZHRWeDZLVWplWTVnZStzcGdCRTEyR2NPdwpxMUhJb0NrekVBMk5HOGRNRGM4dkQ5WHBQWGwxdW5veWN4Y0VMeFVRSC9PRlc4eHJxNU9vcXVYUkxMMnlKcXNGCmlvM2lJV3EvU09Yajc4MVp6MW5BV1JSNCtSYW1KWjlOcUNjb1Z3b3R6VzI1UWJKWWJ3QzJOSkNENEFwOUtXUjUKU2w2blk3NVMybEdSRENsQkNnN2VRdzcwU25seW5mb3RaTUpKdmFzbStrOWR3U0xtSDh2RDNMMGNGOW5SOENTSgpiTjBiZzczeVlWRHgyY3JRYk0zcko4dUJnY3BsWlRpUy91SXJ2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: my-cert + vaultRole: demo-role +``` + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: tls + namespace: demo +type: kubernetes.io/tls +data: + tls.crt: cm9vdA== + tls.key: cm9vdA== +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/token.md b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/token.md new file mode 100644 index 000000000..8ba7f9963 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/token.md @@ -0,0 +1,62 @@ +--- +title: Connect to Vault using Token Auth Method +menu: + docs_v2025.11.21: + identifier: token-auth-methods + name: Token + parent: auth-methods-vault-server-crds + weight: 30 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Connect to Vault using Token Auth Method + +The KubeVault operator uses an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) to connect to an externally provisioned Vault server. To use [Token Authentication](https://www.vaultproject.io/docs/auth/token.html#token-auth-method), follow the steps below to create an appropriate AppBinding: + +- You have to specify `spec.secret` in the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding). + +- The type of the specified secret must be `kubevault.com/token`. + +- The specified secret data must have the following key: + - `Secret.Data["token"]` : `Required`. Specifies the Vault authentication token. + +- The specified secret must be in AppBinding's namespace. + +Sample AppBinding and Secret is given below: + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + secret: + name: vault-token + clientConfig: + service: + name: vault + scheme: HTTPS + port: 8200 + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9ERXlNamN3TkRVNU1qVmFGdzB5T0RFeU1qUXdORFU1TWpWYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMVhid2wyQ1NNc2VQTU5RRzhMd3dUVWVOCkI1T05oSTlDNzFtdUoyZEZjTTlUc1VDQnlRRk1weUc5dWFvV3J1ZDhtSWpwMVl3MmVIUW5udmoybXRmWGcrWFcKSThCYkJUaUFKMWxMMFE5MlV0a1BLczlXWEt6dTN0SjJUR1hRRDhhbHZhZ0JrR1ViOFJYaUNqK2pnc1p6TDRvQQpNRWszSU9jS0xnMm9ldFZNQ0hwNktpWTBnQkZiUWdJZ1A1TnFwbksrbU02ZTc1ZW5hWEdBK2V1d09FT0YwV0Z2CmxGQmgzSEY5QlBGdTJKbkZQUlpHVDJKajBRR1FNeUxodEY5Tk1pZTdkQnhiTWhRVitvUXp2d1EvaXk1Q2pndXQKeDc3d29HQ2JtM0o4cXRybUg2Tjl6Tlc3WlR0YTdLd05PTmFoSUFEMSsrQm5rc3JvYi9BYWRKT0tMN2dLYndJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFXeWFsdUt3Wk1COWtZOEU5WkdJcHJkZFQyZnFTd0lEOUQzVjN5anBlaDVCOUZHN1UKSS8wNmpuRVcyaWpESXNHNkFDZzJKOXdyaSttZ2VIa2Y2WFFNWjFwZHRWeDZLVWplWTVnZStzcGdCRTEyR2NPdwpxMUhJb0NrekVBMk5HOGRNRGM4dkQ5WHBQWGwxdW5veWN4Y0VMeFVRSC9PRlc4eHJxNU9vcXVYUkxMMnlKcXNGCmlvM2lJV3EvU09Yajc4MVp6MW5BV1JSNCtSYW1KWjlOcUNjb1Z3b3R6VzI1UWJKWWJ3QzJOSkNENEFwOUtXUjUKU2w2blk3NVMybEdSRENsQkNnN2VRdzcwU25seW5mb3RaTUpKdmFzbStrOWR3U0xtSDh2RDNMMGNGOW5SOENTSgpiTjBiZzczeVlWRHgyY3JRYk0zcko4dUJnY3BsWlRpUy91SXJ2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +``` + +```yaml +apiVersion: v1 +data: + token: cm9vdA== +kind: Secret +metadata: + name: vault-token + namespace: demo +type: kubevault.com/token +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/userpass.md b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/userpass.md new file mode 100644 index 000000000..9c4cd6eb6 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/userpass.md @@ -0,0 +1,80 @@ +--- +title: Connect to Vault using Userpass Auth Method +menu: + docs_v2025.11.21: + identifier: userpass-auth-methods + name: Userpass + parent: auth-methods-vault-server-crds + weight: 35 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Connect to Vault using Userpass Auth Method + +The KubeVault operator uses an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) to connect to an externally provisioned Vault server. For [Userpass authentication](https://www.vaultproject.io/docs/auth/userpass.html), it has to be enabled and configured in the Vault server. Follow the steps below to create an appropriate AppBinding: + +- You have to specify `spec.secret` in the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding). + +- The type of the specified secret must be `kubernetes.io/basic-auth`. + +- The specified secret data must have the following key: + - `Secret.Data["username"]` : `Required`. Specifies the username used for authentication. + - `Secret.Data["password"]` : `Required`. Specifies the password used for authentication. + +- The specified secret must be in AppBinding's namespace. + +- The additional information required for the Userpass authentication method can be provided as AppBinding's `spec.parameters`. + + ```yaml + spec: + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: my-userpass + ``` + + - `path` : `optional`. Specifies the path where the Userpass auth is enabled in Vault. If this path is not provided, the path will be set by default path `userpass`. + +Sample AppBinding and Secret is given below: + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + secret: + name: userpass-cred + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: my-userpass + clientConfig: + service: + name: vault + scheme: HTTPS + port: 8200 + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9ERXlNamN3TkRVNU1qVmFGdzB5T0RFeU1qUXdORFU1TWpWYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMVhid2wyQ1NNc2VQTU5RRzhMd3dUVWVOCkI1T05oSTlDNzFtdUoyZEZjTTlUc1VDQnlRRk1weUc5dWFvV3J1ZDhtSWpwMVl3MmVIUW5udmoybXRmWGcrWFcKSThCYkJUaUFKMWxMMFE5MlV0a1BLczlXWEt6dTN0SjJUR1hRRDhhbHZhZ0JrR1ViOFJYaUNqK2pnc1p6TDRvQQpNRWszSU9jS0xnMm9ldFZNQ0hwNktpWTBnQkZiUWdJZ1A1TnFwbksrbU02ZTc1ZW5hWEdBK2V1d09FT0YwV0Z2CmxGQmgzSEY5QlBGdTJKbkZQUlpHVDJKajBRR1FNeUxodEY5Tk1pZTdkQnhiTWhRVitvUXp2d1EvaXk1Q2pndXQKeDc3d29HQ2JtM0o4cXRybUg2Tjl6Tlc3WlR0YTdLd05PTmFoSUFEMSsrQm5rc3JvYi9BYWRKT0tMN2dLYndJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFXeWFsdUt3Wk1COWtZOEU5WkdJcHJkZFQyZnFTd0lEOUQzVjN5anBlaDVCOUZHN1UKSS8wNmpuRVcyaWpESXNHNkFDZzJKOXdyaSttZ2VIa2Y2WFFNWjFwZHRWeDZLVWplWTVnZStzcGdCRTEyR2NPdwpxMUhJb0NrekVBMk5HOGRNRGM4dkQ5WHBQWGwxdW5veWN4Y0VMeFVRSC9PRlc4eHJxNU9vcXVYUkxMMnlKcXNGCmlvM2lJV3EvU09Yajc4MVp6MW5BV1JSNCtSYW1KWjlOcUNjb1Z3b3R6VzI1UWJKWWJ3QzJOSkNENEFwOUtXUjUKU2w2blk3NVMybEdSRENsQkNnN2VRdzcwU25seW5mb3RaTUpKdmFzbStrOWR3U0xtSDh2RDNMMGNGOW5SOENTSgpiTjBiZzczeVlWRHgyY3JRYk0zcko4dUJnY3BsWlRpUy91SXJ2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +``` + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: userpass-cred + namespace: demo +type: kubernetes.io/basic-auth +data: + username: cm9vdA== + password: cm9vdA== +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/_index.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/_index.md new file mode 100755 index 000000000..a3fe6887e --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/_index.md @@ -0,0 +1,17 @@ +--- +title: Vault Server Storage +menu: + docs_v2025.11.21: + identifier: storage-vault-server-crds + name: Storage + parent: vault-server-crds-concepts + weight: 25 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/azure.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/azure.md new file mode 100644 index 000000000..128239632 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/azure.md @@ -0,0 +1,101 @@ +--- +title: Azure | Vault Server Storage +menu: + docs_v2025.11.21: + identifier: azure-storage + name: Azure + parent: storage-vault-server-crds + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Azure + +In Azure storage backend, Vault data will be stored in [Azure Storage Container](https://azure.microsoft.com/en-us/services/storage/). Vault documentation for azure storage can be found in [here](https://www.vaultproject.io/docs/configuration/storage/azure.html). + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault-with-azure + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + azure: + accountName: "vault-ac" + accountKeySecret: "azure-cred" + container: "my-vault-storage" +``` + +## spec.backend.azure + +To use Azure as backend storage in Vault specify `spec.backend.azure` in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. + +```yaml +spec: + backend: + azure: + accountName: + accountKeySecret: + container: + maxParallel: +``` + +Here, we are going to describe the various attributes of the `spec.backend.azure` field. + +### azure.accountName + +`azure.accountName` is a required field that specifies the Azure Storage account name. + +```yaml +spec: + backend: + azure: + accountName: "my-vault-storage" +``` + +### azure.accountKeySecret + +`azure.accountKeySecret` is a required field that specifies the name of the secret containing Azure Storage account key. The secret contains the following key: + +- `account_key` + +```yaml +spec: + backend: + azure: + accountKeySecret: "azure-storage-key" +``` + +### azure.container + +`azure.container` is a required field that specifies the Azure Storage Blob container name. + +```yaml +spec: + backend: + azure: + container: "my-vault-storage" +``` + +### azure.maxParallel + +`maxParallel` is an optional field that specifies the maximum number of parallel operations to take place. This field accepts integer value. If this field is not specified, then Vault will set value to `128`. + +```yaml +spec: + backend: + azure: + maxParallel: 124 +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/consul.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/consul.md new file mode 100644 index 000000000..9f19544a7 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/consul.md @@ -0,0 +1,322 @@ +--- +title: Consul | Vault Server Storage +menu: + docs_v2025.11.21: + identifier: consul-storage + name: Consul + parent: storage-vault-server-crds + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Consul + +In the Consul storage backend, Vault data will be stored in the consul storage container. Vault documentation for Consul storage backend can be found in [here](https://www.vaultproject.io/docs/configuration/storage/consul.html) + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + backend: + consul: + address: "http://my-service.demo.svc:8500" + path: "vault" + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys +``` + +If you need to disable the server from executing the `mlock` syscall, you can provide [disable_mlock](https://www.vaultproject.io/docs/configuration/#disable_mlock) in a ConfigMap and mention the name in `spec.configSource.configMap.name`. + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: extra-config + namespace: demo +data: + vault.hcl: | + disable_mlock = true +``` + +To use Consul as a storage backend, first, we need to deploy Consul. Documentation for deploying Consul in Kubernetes can be found [here](https://www.consul.io/docs/k8s/installation/install). Below is an example yaml for deploying Consul suitable for demo purposes: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: consul-example + namespace: demo + labels: + app: consul +spec: + containers: + - name: example + image: "consul:latest" + restartPolicy: Never +--- +kind: Service +apiVersion: v1 +metadata: + name: my-service + namespace: demo +spec: + selector: + app: consul + ports: + - protocol: TCP + port: 8500 + type: NodePort +``` + +## spec.backend.consul + +To use Consul as backend storage in Vault, we need to specify `spec.backend.consul` in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. +More information about the Consul backend storage can be found in [here](https://www.vaultproject.io/docs/configuration/storage/consul.html) + +```yaml +spec: + backend: + consul: + address: + checkTimeout: + consistencyMode: + disableRegistration: + maxParallel: + path: + scheme: + service: + serviceTags: + serviceAddress: + aclTokenSecretName: + sessionTTL: + lockWaitTime: + tlsSecretName: + tlsMinVersion: + tlsSkipVerify: +``` + +Here, we are going to describe the various attributes of the `spec.backend.consul` field. + +### consul.address + +Specifies the address of the Consul agent to communicate with. This can be an IP address, DNS record, or Unix socket. It is recommended that you communicate with a local Consul agent; do not communicate directly with a server. + +```yaml +spec: + backend: + consul: + address: "127.0.0.1:8500" +``` + +### consul.checkTimeout + +Specifies the check interval used to send health check information back to Consul. This is specified using a label suffix like "30s" or "1h" + +```yaml +spec: + backend: + consul: + checkTimeout: "5s" +``` + +### consul.consistencyMode + +Specifies the Consul consistency mode. Possible values are "default" or "strong". + +```yaml +spec: + backend: + consul: + consistencyMode: "default" +``` + +### consul.disableRegistration + +Specifies whether Vault should register itself with Consul. + +```yaml +spec: + backend: + consul: + disableRegistration: "false" +``` + +### consul.maxParallel + +Specifies the maximum number of concurrent requests to Consul. + +```yaml +spec: + backend: + consul: + maxParallel: "128" +``` + +### consul.path + +Specifies the path in Consul's key-value store where Vault data will be stored. + +```yaml +spec: + backend: + consul: + path: "vault" +``` + +### consul.scheme + +Specifies the scheme to use when communicating with Consul. This can be set to "http" or "https". It is highly recommended you communicate with Consul over https over non-local connections. When communicating over a Unix socket, this option is ignored. + +```yaml +spec: + backend: + consul: + scheme: "http" +``` + +### consul.service + +Specifies the name of the service to register in Consul. + +```yaml +spec: + backend: + consul: + service: "vault" +``` + +### consul.serviceTags + +Specifies a comma-separated list of tags to attach to the service registration in Consul. + +```yaml +spec: + backend: + consul: + serviceTags: "" +``` + +### consul.serviceAddress + +Specifies a service-specific address to set on the service registration in Consul. If unset, Vault will use what it knows to be the HA redirect address - which is usually desirable. Setting this parameter to `""` will tell Consul to leverage the configuration of the node the service is registered on dynamically. + +```yaml +spec: + backend: + consul: + serviceAddress: "" +``` + +### consul.aclTokenSecretName + +Specifies the secret name that contains ACL token with permission to read and write from the path in Consul's key-value store. ACL Token should be stored in `data["aclToken"]=` + +```yaml +spec: + backend: + consul: + aclTokenSecretName: aclcred +``` + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: aclcred + namespace: demo +data: + aclToken: |- + ZGF0YQ== +``` + +### consul.sessionTTL + +Specifies the minimum allowed session TTL. The consul server has a lower limit of 10s on the session TTL by default. The value of session_ttl here cannot be lesser than 10s unless the session_ttl_min on the consul server's configuration has a lesser value. + +```yaml +spec: + backend: + consul: + sessionTTL: "15s" +``` + +### consul.lockWaitTime + +Specifies the wait time before a lock acquisition is made. This affects the minimum time it takes to cancel a lock acquisition. + +```yaml +spec: + backend: + consul: + lockWaitTime: "15s" +``` + +### consul.tlsSecretName + +Specifies the secret name that contains tls_ca_file, tls_cert_file and tls_key_file for consul communication. + +```yaml +spec: + backend: + consul: + tlsSecretName: tls +``` + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: tls + namespace: demo +data: + ca.crt: eyJtc2ciOiJleGFtcGxlIn0= + client.crt: eyJtc2ciOiJleGFtcGxlIn0= + client.key: eyJtc2ciOiJleGFtcGxlIn0= +``` + +### consul.tlsMinVersion + +Specifies the minimum TLS version to use. Accepted values are "tls10", "tls11" or "tls12". + +```yaml +spec: + backend: + consul: + tlsMinVersion: "tls12" +``` + +### consul.tlsSkipVerify + +Disable verification of TLS certificates. Using this option is highly discouraged. It is a `boolean` type variable. + +```yaml +spec: + backend: + consul: + tlsSkipVerify: false +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/dynamodb.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/dynamodb.md new file mode 100644 index 000000000..f7944f98d --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/dynamodb.md @@ -0,0 +1,167 @@ +--- +title: Dynamodb | Vault Server Storage +menu: + docs_v2025.11.21: + identifier: dynamodb-storage + name: Dynamodb + parent: storage-vault-server-crds + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# DynamoDB + +In DynamoDB storage backend, Vault data will be stored in [DynamoDB](https://aws.amazon.com/dynamodb/). Vault documentation for DynamoDB storage can be found in [here](https://www.vaultproject.io/docs/configuration/storage/dynamodb.html). + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault-with-dynamodb + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + dynamodb: + table: "my-vault-table" + region: "us-west-1" + readCapacity: 5 + writeCapacity: 5 +``` + +## spec.backend.dynamodb + +To use dynamoDB as backend storage in Vault specify `spec.backend.dynamodb` in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. + +```yaml +spec: + backend: + dynamodb: + table: + region: + endpoint: + haEnabled: + readCapacity: + writeCapacity: + credentialSecret: + sessionTokenSecret: + maxParallel: +``` + +Here, we are going to describe the various attributes of the `spec.backend.dynamodb` field. + +### dynamodb.table + +`dynamodb.table` is a required field that specifies the name of the DynamoDB table. If the specified table does not exist, then Vault will create it during initialization. If it is not initialized, then Vault will set value to `vault-dynamodb-backend`. + +```yaml +spec: + backend: + dynamodb: + table: "my-vault-table" +``` + +### dynamodb.endpoint + +`dynamodb.endpoint` is an optional field that specifies an alternative, AWS compatible, DynamoDB endpoint. + +```yaml +spec: + backend: + dynamodb: + endpoint: "endpoint.com" +``` + +### dynamodb.region + +`dynamodb.region` is an optional field that specifies the AWS region. If this field is not specified, then Vault will set value to `us-east-1`. + +```yaml +spec: + backend: + dynamodb: + region: "us-east-1" +``` + +### dynamodb.credentialSecret + +`dynamodb.credentialSecret` is an optional field that specifies the secret name containing AWS access key and AWS secret key. The secret contains the following keys: + +- `access_key` +- `secret_key` + +Leaving the `access_key` and `secret_key` fields empty will cause Vault to attempt to retrieve credentials from the AWS metadata service. + +```yaml +spec: + backend: + dynamodb: + credentialSecret: "aws-credential" +``` + +### dynamodb.sessionTokenSecret + +`dynamodb.sessionTokenSecret` is an optional field that specifies the secret name containing the AWS session token. The secret contains the following key: + +- `session_token` + +```yaml +spec: + backend: + dynamodb: + sessionTokenSecret: "aws-session-token" +``` + +### dynamodb.maxParallel + +`maxParallel` is an optional field that specifies the maximum number of parallel operations to take place. This field accepts integer value. If this field is not specified, then Vault will set value to `128`. + +```yaml +spec: + backend: + dynamodb: + maxParallel: 124 +``` + +### dynamodb.readCapacity + +`dynamodb.readCapacity` is an optional field that specifies the maximum number of reads consumed per second on the table. If it is not specified, then Vault will set value to `5`. + +```yaml +spec: + backend: + dynamodb: + readCapacity: 10 +``` + +### dynamodb.writeCapacity + +`dynamodb.writeCapacity` is an optional field that specifies the maximum number of writes performed per second on the table. If it is not specified, then Vault will set value to `5`. + +```yaml +spec: + backend: + dynamodb: + writeCapacity: 10 +``` + +### dynamodb.haEnabled + +`dynamodb.haEnabled` is an optional field that specifies whether this backend should be used to run Vault in high availability mode. This field accepts boolean value. The default value is `false`. + +```yaml +spec: + backend: + dynamodb: + haEnabled: true +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/etcd.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/etcd.md new file mode 100644 index 000000000..6557a0f99 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/etcd.md @@ -0,0 +1,140 @@ +--- +title: Etcd | Vault Server Storage +menu: + docs_v2025.11.21: + identifier: etcd-storage + name: Etcd + parent: storage-vault-server-crds + weight: 20 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Etcd + +In Etcd storage backend, Vault data will be stored in [Etcd](https://etcd.io/). Vault documentation for Etcd storage can be found in [here](https://www.vaultproject.io/docs/configuration/storage/etcd.html). + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault-with-etcd + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + etcd: + address: "http://example.etcd.svc:2379" + etcdApi: "v3" +``` + +## spec.backend.etcd + +To use Etcd as storage backend in Vault specify `spec.backend.etcd` in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. + +```yaml +spec: + backend: + etcd: + address: "http://example.etcd.svc:2379" + etcdApi: "v3" +``` + +Here, we are going to describe the various attributes of the `spec.backend.etcd` field. + +### etcd.address + +`etcd.address` is a required field that specifies the addresses of the etcd instances. + +```yaml +spec: + backend: + etcd: + address: "http://example.etcd.svc:2379" +``` + +### etcd.haEnable + +`etcd.haEnable` is an optional field that specifies if high availability should be enabled. This field accepts boolean value. The default value is `false`. + +```yaml +spec: + backend: + etcd: + haEnable: true +``` + +### etcd.etcdApi + +`etcd.etcdApi` is an optional field that specifies the version of the API to communicate with etcd. If this field is not specified, then Vault will derive it automatically. If the cluster version is 3.1+ and there has been no data written using the v2 API, the auto-detected default is v3. + +```yaml +spec: + backend: + etcd: + etcdApi: "v3" +``` + +### etcd.path + +`etcd.path` is an optional field that specifies the path in etcd where Vault data will be stored. If this field is not specified, then Vault will set default value `/vault/`. + +```yaml +spec: + backend: + etcd: + path: "/data/" +``` + +### etcd.sync + +`etcd.sync` is an optional field that specifies whether to sync a list of available etcd services on startup. This field accepts boolean value. The default value is `false`. + +```yaml +spec: + backend: + etcd: + sync: true +``` + +### etcd.discoverySrv + +`etcd.discoverySrv` is an optional field that specifies the domain name to query for SRV records describing cluster endpoints. If this field is not specified, then Vault will set default value `example.com` + +```yaml +spec: + backend: + etcd: + discoverySrv: "example.com" +``` + +### etcd.credentialSecretName + +`etcd.credentialSecretName` is an optional field that specifies the secret name that contains username and password to use when authenticating with the etcd server. The secret contains the following keys: + +- `username` +- `password` + +```yaml +spec: + backend: + etcd: + credentialSecretName: "etcd-credential" +``` + +### etcd.tlsSecretName + +`etcd.tlsSecretName` is an optional field that specifies the secret name that contains TLS assets for etcd communication. The secret contains following keys: + +- `tls_ca_file` +- `tls_cert_file` +- `tls_key_file` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/filesystem.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/filesystem.md new file mode 100644 index 000000000..6db155aca --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/filesystem.md @@ -0,0 +1,144 @@ +--- +title: Filesystem | Vault Server Storage +menu: + docs_v2025.11.21: + identifier: filesystem-storage + name: Filesystem + parent: storage-vault-server-crds + weight: 20 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Filesystem + +The [Filesystem storage backend](https://www.vaultproject.io/docs/configuration/storage/filesystem.html) stores Vault data on the filesystem using a standard directory structure. As the Filesystem backend does not support high availability (HA), it can be used for **single node** setups(i.e. vaultserver.spec.replicas: 1). A `VolumeClaimTemplate` can be specified to create (or reuse if already exist) a [PersistentVolumeClaim](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) so that Vault data can be stored in the corresponding [PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/). + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + replicas: 1 + version: "1.2.3" + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + backend: + file: + path: /mnt/vault/data + volumeClaimTemplate: + metadata: + name: vault-pvc + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 50Mi + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys +``` + +## spec.backend.file + +To use file system as storage backend in Vault server, specify the `spec.backend.file` in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. + +```yaml +spec: + backend: + file: + path: /mnt/vault/data + volumeClaimTemplate: + metadata: + name: vault-pvc + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 50Mi +``` + +Here, we are going to describe various attributes of the `spec.backend.file` field. + +### file.path + +`file.path` is a `required` field that specifies the absolute path to the directory where the data will be stored. + +```yaml +backend: + file: + path: /mnt/vault/data +``` + +### file.volumeClaimTemplate + +`file.volumeClaimTemplate` is a `required` field that specifies a [PersistentVolumeClaim](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) object that will provide storage for Vault server. The KubeVault operator will use the PVC if it already exists, otherwise, it will create a new PVC. On the deletion of VaultServer CRD, the PVC will be left intact. To clean up, you must delete the PVC manually. + +```yaml +file: + volumeClaimTemplate: + metadata: + name: vault-pvc + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 50Mi +``` + +#### file.volumeClaimTemplate.metadata + +`volumeClaimTemplate.metadata` is an `optional` field that specifies a standard object's metadata. The following fields can be provided: + +- `name` : `optional`. Specifies a name that uniquely identifies this object within the current namespace. Default to the name of VaultServer. +- `labels` : `optional`. Specifies a map of string keys and values that can be used to organize and categorize objects. Default to the labels of the VaultServer. + +```yaml +volumeClaimTemplate: + metadata: + name: vault-pvc + labels: + app: vault +``` + +#### file.volumeClaimTemplate.spec + +`volumeClaimTemplate.spec` is a `required` field that defines the desired characteristics of a volume. It contains all fields and features of a standard [PersistentVolumeClaim](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) object's spec. + +Sub-fields are given below: + +- `accessModes` +- `selector` +- `resources` +- `volumeName` +- `storageClassName` +- `volumeMode` +- `dataSource` + +```yaml +file: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 50Mi +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/gcs.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/gcs.md new file mode 100644 index 000000000..d090ca2a3 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/gcs.md @@ -0,0 +1,112 @@ +--- +title: GCS | Vault Server Storage +menu: + docs_v2025.11.21: + identifier: gcs-storage + name: GCS + parent: storage-vault-server-crds + weight: 25 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Google Cloud Storage (GCS) + +In Google Cloud Storage (GCS) storage backend, Vault data will be stored in [Google Cloud Storage](https://cloud.google.com/storage/docs/). Vault documentation for GCS storage can be found in [here](https://www.vaultproject.io/docs/configuration/storage/google-cloud-storage.html). + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault-with-gcs + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + gcs: + bucket: "my-vault-storage" + credentialSecret: "my-gcs-credential" +``` + +## spec.backend.gcs + +To use GCS as backend storage in Vault specify `spec.backend.gcs` in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. + +```yaml +spec: + backend: + gcs: + bucket: + chunkSize: + maxParallel: + haEnabled: + credentialSecret: +``` + +Here, we are going to describe the various attributes of the `spec.backend.gcs` field. + +### gcs.bucket + +`gcs.bucket` is a required field that specifies the name of the bucket to use for storage. + +```yaml +spec: + backend: + gcs: + bucket: "my-vault-storage" +``` + +### gcs.chunkSize + +`gcs.chunkSize` is an optional field that specifies the maximum size (in kilobytes) to send in a single request. If this field is not specified, then Vault will set value to `8192`. If this filed is set to 0, Vault will attempt to send the whole object at once, but will not retry any failures. + +```yaml +spec: + backend: + gcs: + chunkSize: "1024" +``` + +### gcs.credentialSecret + +`gcs.credentialSecret` is a required field that specifies the name of the secret containing Google application credential. The secret contains the following key: + +- `sa.json` + +```yaml +spec: + backend: + gcs: + credentialSecret: "google-application-credential" +``` + +### gcs.haEnabled + +`gcs.haEnabled` is an optional field that specifies if high availability mode is enabled. This field accepts boolean value. The default value is `false`. + +```yaml +spec: + backend: + gcs: + haEnabled: true +``` + +### gcs.maxParallel + +`maxParallel` is an optional field that specifies the maximum number of parallel operations to take place. This field accepts integer value. If this field is not specified, then Vault will set value to `128`. + +```yaml +spec: + backend: + gcs: + maxParallel: 124 +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/inmem.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/inmem.md new file mode 100644 index 000000000..841909b2b --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/inmem.md @@ -0,0 +1,46 @@ +--- +title: In Memory | Vault Server Storage +menu: + docs_v2025.11.21: + identifier: inmem-storage + name: In Memory + parent: storage-vault-server-crds + weight: 30 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# In-Memory + +In `In-Memory` backend storage, Vault data will be kept in memory. If the Kubernetes pod on which Vault is running is restarted, then all data will be lost. This is useful for development and experimentation, but the use of this backend is highly discouraged in production. Vault documentation for In-Memory storage can be found in [here](https://www.vaultproject.io/docs/configuration/storage/in-memory.html). + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault-with-inmem + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + inmem: {} +``` + +## spec.backend.inmem + +To use In-Memory as storage backend in Vault specify `spec.backend.inmem` in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. + +```yaml +spec: + backend: + inmem: {} +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/mysql.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/mysql.md new file mode 100644 index 000000000..6641eecae --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/mysql.md @@ -0,0 +1,127 @@ +--- +title: MySQL | Vault Server Storage +menu: + docs_v2025.11.21: + identifier: mysql-storage + name: MySQL + parent: storage-vault-server-crds + weight: 35 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# MySQL + +In MySQL storage backend, Vault data will be stored in MySQL. Vault documentation for MySQL storage can be found in [here](https://www.vaultproject.io/docs/configuration/storage/mysql.html). + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault-with-mysql + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + mysql: + address: "my.mysql.com:3306" + userCredentialSecret: "mysql-cred" +``` + +## spec.backend.mysql + +To use MySQL as backend storage in Vault, specify `spec.backend.mysql` in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. + +```yaml +spec: + backend: + mysql: + address:
+ database: + table: + userCredentialSecret: + tlsCASecret: + maxParallel: +``` + +Here, we are going to describe the various attributes of the `spec.backend.mysql` field. + +### mysql.address + +`mysql.address` is a required field that specifies the address of the MySQL host. + +```yaml +spec: + backend: + mysql: + address: "my.mysql.com:3306" +``` + +### mysql.userCredentialSecret + +`mysql.userCredentialSecret` is a required field that specifies the name of the secret containing MySQL username and password to connect with the database. The secret contains the following fields: + +- `username` +- `password` + +```yaml +spec: + backend: + mysql: + userCredentialSecret: "mysql-cred" +``` + +### mysql.database + +`mysql.database` is an optional field that specifies the name of the database. If the database does not exist, Vault will attempt to create it. If it is not specified, then Vault will set vault `vault`. + +```yaml +spec: + backend: + mysql: + database: "my_vault" +``` + +### mysql.table + +`mysql.table` is an optional field that specifies the name of the table. If the table does not exist, Vault will attempt to create it. If it is not specified, then Vault will set value to `vault`. + +```yaml +spec: + backend: + mysql: + table: "vault_data" +``` + +### mysql.tlsCASecret + +`mysql.tlsCASecret` is an optional field that specifies the name of the secret containing the CA certificate to connect using TLS. The secret contains the following fields: + +- `tls_ca_file` + +```yaml +spec: + backend: + mysql: + tlsCASecret: "mysql-ca" +``` + +### mysql.maxParallel + +`maxParallel` is an optional field that specifies the maximum number of parallel operations to take place. This field accepts integer value. If this field is not specified, then Vault will set value to `128`. + +```yaml +spec: + backend: + mysql: + maxParallel: 124 +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/overview.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/overview.md new file mode 100644 index 000000000..02c4183b9 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/overview.md @@ -0,0 +1,47 @@ +--- +title: Overview +menu: + docs_v2025.11.21: + identifier: storage-overview + name: Overview + parent: storage-vault-server-crds + weight: 1 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Storage Backend + +## Configuring Storage Backend + +```yaml +spec: + backend: + : + ... +``` + +Here, we are going to describe the various attributes of the `spec.backend` field. + +List of supported modes: + +- [Azure](/docs/v2025.11.21/concepts/vault-server-crds/storage/azure) +- [Consul](/docs/v2025.11.21/concepts/vault-server-crds/storage/consul) +- [DynamoDB](/docs/v2025.11.21/concepts/vault-server-crds/storage/dynamodb) +- [Etcd](/docs/v2025.11.21/concepts/vault-server-crds/storage/etcd) +- [Filesystem](/docs/v2025.11.21/concepts/vault-server-crds/storage/filesystem) +- [GCS](/docs/v2025.11.21/concepts/vault-server-crds/storage/gcs) +- [Inmem](/docs/v2025.11.21/concepts/vault-server-crds/storage/inmem) +- [MySQL](/docs/v2025.11.21/concepts/vault-server-crds/storage/mysql) +- [PostgreSQL](/docs/v2025.11.21/concepts/vault-server-crds/storage/postgresql) +- [Raft](/docs/v2025.11.21/concepts/vault-server-crds/storage/raft) +- [S3](/docs/v2025.11.21/concepts/vault-server-crds/storage/s3) +- [Swift](/docs/v2025.11.21/concepts/vault-server-crds/storage/swift) diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/postgresql.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/postgresql.md new file mode 100644 index 000000000..7533ce7c0 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/postgresql.md @@ -0,0 +1,87 @@ +--- +title: PostgreSQL | Vault Server Storage +menu: + docs_v2025.11.21: + identifier: postgresql-storage + name: PostgreSQL + parent: storage-vault-server-crds + weight: 40 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# PostgreSQL + +In PostgreSQL storage backend, Vault data will be stored in [PostgreSQL](https://www.postgresql.org/). Vault documentation for PostgreSQL storage can be found in [here](https://www.vaultproject.io/docs/configuration/storage/postgresql.html). + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault-with-postgresql + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + postgresql: + connectionURLSecret: "my-postgres-conn" +``` + +## spec.backend.postgresql + +To use PostgreSQL as backend storage in Vault specify `spec.backend.postgresql` in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. + +```yaml +spec: + backend: + postgresql: + connectionURLSecret: + table: + maxParallel: +``` + +Here, we are going to describe the various attributes of the `spec.backend.postgresql` field. + +### postgresql.connectionURLSecret + +`postgresql.connectionURLSecret` is a required field that specifies the name of the secret containing the connection string to use to authenticate and connect to PostgreSQL. The secret contains the following key: + +- `connection_url` + +```yaml +spec: + backend: + postgresql: + connectionURLSecret: "my-postgres-conn" +``` + +### postgresql.table + +`postgresql.table` is an optional field that specifies the name of the table in which to write Vault data. If it is not specified, then Vault will set the value `vault_kv_store`. Vault will not create the table, so this table must exist in the database. + +```yaml +spec: + backend: + postgresql: + table: "vault_data" +``` + +### postgresql.maxParallel + +`maxParallel` is an optional field that specifies the maximum number of parallel operations to take place. This field accepts integer value. If this field is not specified, then Vault will set value to `128`. + +```yaml +spec: + backend: + postgresql: + maxParallel: 124 +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/raft.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/raft.md new file mode 100644 index 000000000..3103e8f2d --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/raft.md @@ -0,0 +1,145 @@ +--- +title: Raft | Vault Server Storage +menu: + docs_v2025.11.21: + identifier: raft-storage + name: Raft + parent: storage-vault-server-crds + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Raft + +In the `Raft` storage backend, vault data will be stored in provided file system path. Vault documentation for `Raft` storage backend can be found in [here](https://www.vaultproject.io/docs/configuration/storage/raft.html). + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: default +spec: + replicas: 3 + version: 1.7.3 + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: WipeOut + +``` + +## spec.backend.raft + +To use `Raft` as backend storage in Vault, we need to specify `spec.backend.raft` in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. +More information about the `Raft` backend storage can be found in [here](https://www.vaultproject.io/docs/configuration/storage/raft.html) + +```yaml +spec: + backend: + raft: + path: + performanceMultiplier: + trailingLogs: + snapshotThreshold: + maxEntrySize: + autoPilotReconcileInterval: +``` + +Here, we are going to describe the various attributes of the `spec.backend.raft` field. + +### raft.path + +`Path` specifies the filesystem path where the vault data gets stored. This value can be overridden by setting the `VAULT_RAFT_PATH` environment variable. `default: ""` + +```yaml +spec: + backend: + raft: + path: "/vault/data" +``` + +### raft.performanceMultiplier + +An integer multiplier used by servers to scale key Raft timing parameters. Tuning this affects the time it takes Vault to detect leader failures and to perform leader elections, at the expense of requiring more network and CPU resources for better performance. `default: 0` +```yaml +spec: + backend: + raft: + performanceMultiplier: 0 +``` + +### raft.trailingLogs + +This controls how many log entries are left in the log store on disk after a snapshot is made. `default: 10000` +```yaml +spec: + backend: + raft: + trailingLogs: 10000 +``` + +### raft.snapshotThreshold + +This controls the minimum number of raft commit entries between snapshots that are saved to disk. `default: 8192` +```yaml +spec: + backend: + raft: + snapshotThreshold: 8192 +``` + +### raft.maxEntrySize + +This configures the maximum number of bytes for a raft entry. It applies to both Put operations and transactions. `default: 1048576` +```yaml +spec: + backend: + raft: + maxEntrySize: 1048576 +``` + +### raft.autoPilotReconcileInterval + +This is the interval after which autopilot will pick up any state changes. `default: ""` +```yaml +spec: + backend: + raft: + autoPilotReconcileInterval: "" +``` \ No newline at end of file diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/s3.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/s3.md new file mode 100644 index 000000000..2ef9afe6c --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/s3.md @@ -0,0 +1,154 @@ +--- +title: AWS S3 | Vault Server Storage +menu: + docs_v2025.11.21: + identifier: s3-storage + name: AWS S3 + parent: storage-vault-server-crds + weight: 45 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# AWS S3 + +In S3 storage backend, Vault data will be stored in [AWS S3](https://aws.amazon.com/s3/) bucket. Vault documentation for S3 storage can be found in [here](https://www.vaultproject.io/docs/configuration/storage/s3.html). + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault-with-s3 + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + s3: + bucket: "my-vault-bucket" + region: "us-west-1" + credentialSecret: "aws-credential" +``` + +## spec.backend.s3 + +To use S3 as backend storage in Vault specify `spec.backend.s3` in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. + +```yaml +spec: + backend: + s3: + bucket: + endpoint: + region: + credentialSecret: + sessionTokenSecret: + maxParallel: + forcePathStyle: + disableSSL: +``` + +Here, we are going to describe the various attributes of the `spec.backend.s3` field. + +### s3.bucket + +`s3.bucket` is a required field that specifies the name of the bucket to use for storage. + +```yaml +spec: + backend: + s3: + bucket: "my-vault-storage" +``` + +### s3.endpoint + +`s3.endpoint` is an optional field that specifies an alternative, AWS compatible, S3 endpoint. + +```yaml +spec: + backend: + s3: + endpoint: "endpoint.com" +``` + +### s3.region + +`s3.region` is an optional field that specifies the AWS region. If this field is not specified, then Vault will set value to `us-east-1`. + +```yaml +spec: + backend: + s3: + region: "us-east-1" +``` + +### s3.credentialSecret + +`s3.credentialSecret` is an optional field that specifies the secret name containing AWS access key and AWS secret key. The secret contains the following keys: + +- `access_key` +- `secret_key` + +Leaving the `access_key` and `secret_key` fields empty will cause Vault to attempt to retrieve credentials from the AWS metadata service. + +```yaml +spec: + backend: + s3: + credentialSecret: "aws-credential" +``` + +### s3.sessionTokenSecret + +`s3.sessionTokenSecret` is an optional field that specifies the secret name containing the AWS session token. The secret contains the following key: + +- `session_token` + +```yaml +spec: + backend: + s3: + sessionTokenSecret: "aws-session-token" +``` + +### s3.maxParallel + +`maxParallel` is an optional field that specifies the maximum number of parallel operations to take place. This field accepts integer value. If this field is not specified, then Vault will set value to `128`. + +```yaml +spec: + backend: + s3: + maxParallel: 124 +``` + +### s3.forcePathStyle + +`s3.forcePathStyle` is an optional field that specifies whether to use host bucket-style domains with the configured endpoint. This field accepts boolean value. The default value is `false`. + +```yaml +spec: + backend: + s3: + forcePathStyle: true +``` + +### s3.disableSSL + +`s3.disableSSL` is an optional field that specifies if SSL should be used for the endpoint connection. This field accepts boolean value. The default value is `false`. + +```yaml +spec: + backend: + s3: + disableSSL: true +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/storage/swift.md b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/swift.md new file mode 100644 index 000000000..a810a9e06 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/storage/swift.md @@ -0,0 +1,198 @@ +--- +title: OpenStack Swift | Vault Server Storage +menu: + docs_v2025.11.21: + identifier: swift-storage + name: OpenStack Swift + parent: storage-vault-server-crds + weight: 50 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Swift + +In Swift storage backend, Vault data will be stored in [OpenStack Swift Container](http://docs.openstack.org/developer/swift/). Vault documentation for Swift storage can be found in [here](https://www.vaultproject.io/docs/configuration/storage/swift.html). + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault-with-swift + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + swift: + authURL: "https://auth.cloud.ovh.net/v2.0/" + container: "my-vault-container" + credentialSecret: "os-credential" + region: "BHS1" + tenant: "123456789999" +``` + +## spec.backend.swift + +To use Swift as backend storage in Vault specify `spec.backend.swift` in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. + +```yaml +spec: + backend: + swift: + authURL: + container: + credentialSecret: + region: + tenant: + tenantID: + domain: + projectDomain: + storageURL: + authTokenSecret: +``` + +Here, we are going to describe the various attributes of the `spec.backend.swift` field. + +### swift.authURL + +`swift.authURL` is a required field that specifies the OpenStack authentication endpoint. + +```yaml +spec: + backend: + swift: + authURL: "https://auth.cloud.ovh.net/v2.0/" +``` + +### swift.container + +`swift.container` is a required field that specifies the name of the Swift container. + +```yaml +spec: + backend: + swift: + container: "my-vault-container" +``` + +### swift.credentialSecret + +`swift.credentialSecret` is a required field that specifies the name of the secret containing the OpenStack account/username and password. The secret contains the following keys: + +- `username` +- `password` + +```yaml +spec: + backend: + swift: + credentialSecret: "os-credential" +``` + +### swift.tenant + +`swift.tenant` is an optional field that specifies the name of the tenant. If it is not specified, then Vault will set the value to the default tenant of the username. + +```yaml +spec: + backend: + swift: + tenant: "123456789" +``` + +### swift.region + +`swift.region` is an optional field that specifies the name of the region. + +```yaml +spec: + backend: + swift: + region: "BHS1" +``` + +### swift.tenantID + +`swift.tenantID` is an optional field that specifies the id of the tenant. + +```yaml +spec: + backend: + swift: + tenantID: "11111111" +``` + +### swift.domain + +`swift.domain` is an optional field that specifies the name of the user domain. + +```yaml +spec: + backend: + swift: + domain: "my-domain" +``` + +### swift.projectDomain + +`swift.domain` is an optional field that specifies the name of the project's domain. + +```yaml +spec: + backend: + swift: + projectDomain: "my-project-domain" +``` + +### swift.trustID + +`swift.trustID` is an optional field that specifies the id of the trust. + +```yaml +spec: + backend: + swift: + trustID: "trust-id" +``` + +### swift.storageURL + +`swift.storageURL` is an optional field that specifies the storage URL from alternate authentication. + +```yaml +spec: + backend: + swift: + storageURL: "storage.com" +``` + +### swift.authTokenSecret + +`swift.authTokenSecret` is an optional field that specifies the name of the secret containing auth token from alternate authentication. + +```yaml +spec: + backend: + swift: + authTokenSecret: "auth-token-secret" +``` + +### swift.maxParallel + +`maxParallel` is an optional field that specifies the maximum number of parallel operations to take place. This field accepts integer value. If this field is not specified, then Vault will set value to `128`. + +```yaml +spec: + backend: + swift: + maxParallel: 124 +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/_index.md b/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/_index.md new file mode 100755 index 000000000..1a15f124d --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/_index.md @@ -0,0 +1,17 @@ +--- +title: Vault Unsealer +menu: + docs_v2025.11.21: + identifier: unsealer-vault-server-crds + name: Unsealer + parent: vault-server-crds-concepts + weight: 20 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/aws_kms_ssm.md b/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/aws_kms_ssm.md new file mode 100644 index 000000000..56b38c1c5 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/aws_kms_ssm.md @@ -0,0 +1,88 @@ +--- +title: AWS KMS | Vault Unsealer +menu: + docs_v2025.11.21: + identifier: aws-kms-ssm-unsealer + name: Aws KMS + parent: unsealer-vault-server-crds + weight: 1 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# mode.awsKmsSsm + +To use **awsKmsSsm** mode specify `mode.awsKmsSsm`. In this mode, unseal keys and root token will be stored in [AWS System Manager Parameter store](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html) and they will be encrypted using AWS encryption key. + +```yaml +spec: + unsealer: + mode: + awsKmsSsm: + kmsKeyID: + region: + ssmKeyPrefix: + credentialSecret: + endpoint: +``` + +`mode.awsKmsSsm` has the following fields: + +## awsKmsSsm.kmsKeyID + +`awsKmsSsm.kmsKeyID` is a required field that specifies the ID or ARN of the AWS KMS key to encrypt values. + +```yaml +spec: + unsealer: + mode: + awsKmsSsm: + kmsKeyID: "aaaaa-bbbb-cccc-ddd-eeeeeeee" +``` + +## awsKmsSsm.region + +`awsKmsSsm.region` is a required field that specifies the AWS region. + +```yaml +spec: + unsealer: + mode: + awsKmsSsm: + region: "us-east-1" +``` + +## awsKmsSsm.ssmKeyPrefix + +`awsKmsSsm.ssmKeyPrefix` is an optional field that specifies the prefix for SSM parameters. If this is not specified, then Unsealer will store parameters at the root of SSM. + +```yaml +spec: + unsealer: + mode: + awsKmsSsm: + ssmKeyPrefix: "/cluster/demo" +``` + +## awsKmsSsm.credentialSecret + +`awsKmsSsm.credentialSecret` is an optional field that specifies the name of the secret containing AWS access key and AWS secret key. If this is not specified, then Unsealer will attempt to retrieve credentials from the AWS metadata service. The secret contains the following data fields: + +- `access_key` +- `secret_key` + +```yaml +spec: + unsealer: + mode: + awsKmsSsm: + credentialSecret: "aws-cred" +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/azure_key_vault.md b/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/azure_key_vault.md new file mode 100644 index 000000000..2f2afa2e2 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/azure_key_vault.md @@ -0,0 +1,118 @@ +--- +title: Azure Key Vault | Vault Unsealer +menu: + docs_v2025.11.21: + identifier: azure-key-vault-unsealer + name: Azure Key Vault + parent: unsealer-vault-server-crds + weight: 1 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# mode.azureKeyVault + +To use **azureKeyVault** mode specify `mode.azureKeyVault`. In this mode, unseal keys and root token will be stored in [Azure Key Vault](https://docs.microsoft.com/en-us/azure/key-vault/key-vault-overview) as secret. + +```yaml +spec: + unsealer: + mode: + azureKeyVault: + vaultBaseURL: + tenantID: + clientCertSecret: + aadClientSecret: + cloud: +``` + +`mode.azureKeyVault` has the following fields: + +## azureKeyVault.vaultBaseURL + +`azureKeyVault.vaultBaseURL` is a required field that specifies the Azure key vault URL. + +```yaml +spec: + unsealer: + mode: + azureKeyVault: + vaultBaseURL: "https://myvault.vault.azure.net" +``` + +## azureKeyVault.tenantID + +`azureKeyVault.tenantID` is a required field that specifies Azure Active Directory tenant ID. + +```yaml +spec: + unsealer: + mode: + azureKeyVault: + tenantID: "aaa-ddd-ffff-343455" +``` + +## azureKeyVault.clientCertSecret + +`azureKeyVault.clientCertSecret` is an optional field that specifies the name of the secret containing client cert and client cert password. The secret contains the following fields: + +- `client-cert` +- `client-cert-password` + +```yaml +spec: + unsealer: + mode: + azureKeyVault: + clientCertSecret: "azure-client-cert-cred" +``` + +## azureKeyVault.aadClientSecret + +`azureKeyVault.aadClientSecret` is an optional field that specifies the name of the secret containing client id and client secret of AAD application. The secret contains the following fields: + +- `client-id` +- `client-secret` + +```yaml +spec: + unsealer: + mode: + azureKeyVault: + aadClientSecret: "azure-aad-client-cred" +``` + +## azureKeyVault.useManageIdentity + +`azureKeyVault.useManageIdentity` is an optional field that specifies to use managed service identity for the virtual machine. + +```yaml +spec: + unsealer: + mode: + azureKeyVault: + useManageIdentity: true +``` + +> Note: One of `azureKeyVault.clientCertSecret` or `azureKeyVault.aadClientSecret` or `azureKeyVault.useManageIdentity` has to be specified. + +## azureKeyVault.cloud + +`azureKeyVault.cloud` is an optional field that specifies the cloud environment identifier. If it is not specified, then `AZUREPUBLICCLOUD` will be used as default. + +```yaml +spec: + unsealer: + mode: + azureKeyVault: + cloud: "AZUREGERMANCLOUD" +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/google_kms_gcs.md b/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/google_kms_gcs.md new file mode 100644 index 000000000..054940f80 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/google_kms_gcs.md @@ -0,0 +1,112 @@ +--- +title: Google Cloud KMS | Vault Unsealer +menu: + docs_v2025.11.21: + identifier: google-kms-gcs-unsealer + name: Google Cloud KMS + parent: unsealer-vault-server-crds + weight: 1 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# mode.googleKmsGcs + +To use **googleKmsGcs** mode specify `mode.googleKmsGcs`. In this mode, unseal keys and root token will be stored in [Google Cloud Storage](https://cloud.google.com/storage/docs/) and they will be encrypted using google cryptographic keys. + +```yaml +spec: + unsealer: + mode: + googleKmsGcs: + bucket: + kmsProject: + kmsLocation: + kmsKeyRing: + kmsCryptoKey: + credentialSecret: +``` + +`mode.googleKmsGcs` has the following fields: + +## googleKmsGcs.bucket + +`googleKmsGcs.bucket` is a required field that specifies the name of the bucket to store keys. + +```yaml +spec: + unsealer: + mode: + googleKmsGcs: + bucket: "vault-key-store" +``` + +## googleKmsGcs.kmsProject + +`googleKmsGcs.kmsProject` is a required field that specifies the name of the projects under which the keyring is created. + +```yaml +spec: + unsealer: + mode: + googleKmsGcs: + kmsProject: "project" +``` + +## googleKmsGcs.kmsLocation + +`googleKmsGcs.kmsLocation` is a required field that specifies the location of the keyring. + +```yaml +spec: + unsealer: + mode: + googleKmsGcs: + kmsLocation: "global" +``` + +## googleKmsGcs.kmsKeyRing + +`googleKmsGcs.kmsKeyRing` is a required field that specifies the name of the keyring. + +```yaml +spec: + unsealer: + mode: + googleKmsGcs: + kmsKeyRing: "key-ring" +``` + +## googleKmsGcs.kmsCryptoKey + +`googleKmsGcs.kmsCryptoKey` is a required field that specifies the name of the crypto key. + +```yaml +spec: + unsealer: + mode: + googleKmsGcs: + kmsCryptoKey: "key" +``` + +## googleKmsGcs.credentialSecret + +`googleKmsGcs.credentialSecret` is an optional field that specifies the name of the secret containing google credentials. If this is not specified, then the instance service account will be used (if it is running on google cloud). The secret contains the following field: + +- `sa.json` + +```yaml +spec: + unsealer: + mode: + googleKmsGcs: + credentialSecret: "google-cred" +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/kubernetes_secret.md b/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/kubernetes_secret.md new file mode 100644 index 000000000..7950cd3a7 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/kubernetes_secret.md @@ -0,0 +1,45 @@ +--- +title: Kubernetes Secret | Vault Unsealer +menu: + docs_v2025.11.21: + identifier: kubernetes-secret-unsealer + name: Kubernetes Secret + parent: unsealer-vault-server-crds + weight: 1 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# mode.kubernetesSecret + +To use **kubernetesSecret** mode specify `mode.kubernetesSecret`. In this mode, unseal keys and root token will be stored in a Kubernetes secret. + +```yaml +spec: + unsealer: + mode: + kubernetesSecret: + secretName: +``` + +`mode.kubernetesSecret` has the following fields: + +## kubernetesSecret.secretName + +`kubernetesSecret.secretName` is a required field that specifies the name of the Kubernetes secret. If this secret does not exist, then Unsealer will create it. The secret will be created in the same namespace of [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver). + +```yaml +spec: + unsealer: + mode: + kubernetesSecret: + secretName: "vault-keys" +``` diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/overview.md b/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/overview.md new file mode 100644 index 000000000..f0128a684 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/unsealer/overview.md @@ -0,0 +1,102 @@ +--- +title: Overview +menu: + docs_v2025.11.21: + identifier: unsealer-overview + name: Overview + parent: unsealer-vault-server-crds + weight: 1 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Unsealer + +[Unsealer](https://github.com/kubevault/unsealer) automates the process of [initializing](https://www.vaultproject.io/docs/commands/operator/init.html) and [unsealing](https://www.vaultproject.io/docs/concepts/seal.html#unsealing) Vault running in Kubernetes cluster. Also, it provides facilities to store unseal keys and root token in a secure way. + +## Configuring Unsealer + +To use Unsealer, configure `spec.unsealer` field in [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD . + +```yaml +spec: + unsealer: + secretShares: + secretThresold: + retryPeriodSeconds: + overwriteExisting: + mode: + ... +``` + +Here, we are going to describe the various attributes of the `spec.unsealer` field. + +### unsealer.secretShares + +`unsealer.secretShares` is an optional field that specifies the number of shares to split the master key into. It accepts integer value. The default vault is `5`. + +```yaml +spec: + unsealer: + secretShares: 5 +``` + +> Note: `unsealer.secretShares` must be greater than 1. + +### unsealer.secretThreshold + +`unsealer.secretThreshold` is an optional field that specifies the number of keys required to unseal vault. It accepts integer value. The default vault is `3`. + +```yaml +spec: + unsealer: + secretThreshold: 2 +``` + +> Note: `unsealer.secretThreshold` must be a positive integer and less than or equal to `unsealer.secretShares`. + +### unsealer.retryPeriodSeconds + +`unsealer.retryPeriodSeconds` is an optional field that specifies how often Unsealer will attempt to unseal the vault instance. It accepts integer value. The default vault is `10`. + +```yaml +spec: + unsealer: + retryPeriodSeconds: 15 +``` + +### unsealer.overwriteExisting + +`unsealer.overwriteExisting` is an optional field that specifies Unsealer will overwrite existing unseal keys and root token(if have any). It accepts boolean value. Default vault is `false`. + +```yaml +spec: + unsealer: + overwriteExisting: true +``` + +### unsealer.mode + +`unsealer.mode` is a required field that specifies which mode to use to store unseal keys and root token. + +```yaml +spec: + unsealer: + mode: + ... +``` + +List of supported modes: + +- [kubernetesSecret](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/kubernetes_secret) +- [googleKmsGcs](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/google_kms_gcs) +- [awsKmsSsm](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/aws_kms_ssm) +- [azureKeyVault](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/azure_key_vault) diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/vaultserver.md b/content/docs/v2025.11.21/concepts/vault-server-crds/vaultserver.md new file mode 100644 index 000000000..4c9dc448c --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/vaultserver.md @@ -0,0 +1,363 @@ +--- +title: Vault Server | KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: vaultserver-vault-server-crds + name: Vault Server + parent: vault-server-crds-concepts + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# VaultServer + +## What is VaultServer + +A `VaultServer` is a Kubernetes `CustomResourceDefinition` (CRD) which is used to deploy a HashiCorp Vault server on Kubernetes clusters in a Kubernetes native way. + +When a `VaultServer` is created, the KubeVault operator will deploy a Vault server and create necessary Kubernetes resources required for the Vault server. + +![VaultServer CRD](/docs/v2025.11.21/images/concepts/vault_server.svg) + +## VaultServer CRD Specification + +Like any official Kubernetes resource, a `VaultServer` object has `TypeMeta`, `ObjectMeta`, `Spec` and `Status` sections. + +A sample `VaultServer` object is shown below: + +```yaml +apiVersion: kubevault.com/v1alpha2 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + tls: + issuerRef: + apiGroup: "cert-manager.io" + kind: Issuer + name: vault-issuer + allowedSecretEngines: + namespaces: + from: All + secretEngines: + - mysql + version: 1.10.3 + replicas: 3 + backend: + raft: + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate +``` + +Here, we are going to describe the various sections of the `VaultServer` crd. + +### VaultServer Spec + +VaultServer Spec contains the configuration about how to deploy Vault in the Kubernetes cluster. It also covers automate unsealing of Vault. + +The `spec` section has following parts: + +#### spec.replicas + +`spec.replicas` specifies the number of Vault nodes to deploy. It has to be a positive number. + +```yaml +spec: + replicas: 3 # 3 vault server will be deployed in Kubernetes cluster +``` + +#### spec.version + +Specifies the name of the `VaultServerVersion` CRD. This CRD holds the image name and version of the Vault, Unsealer, and Exporter. To know more information about `VaultServerVersion` CRD see [here](/docs/v2025.11.21/concepts/vault-server-crds/vaultserverversion). + +```yaml +spec: + version: "1.10.3" +``` + +#### spec.tls + +`spec.tls` is an optional field that specifies the TLS policy of Vault nodes. If this is not specified, the KubeVault operator will run in `insecure` mode. + +```yaml +spec: + tls: + issuerRef: + apiGroup: "cert-manager.io" + kind: Issuer + name: vault-issuer +``` + +The server certificate must allow the following wildcard domains: +- `localhost` +- `*..pod` +- `..svc` + + The server certificate must allow the following IP: +- `127.0.0.1` + +#### spec.configSecret + +`spec.configSecret` is an optional field that allows the user to provide extra configuration for Vault. This field accepts a [VolumeSource](https://github.com/kubernetes/api/blob/release-1.11/core/v1/types.go#L47). You can use any Kubernetes supported volume source such as configMap, secret, azureDisk, etc. + +> Please note that the config file name must be `vault.hcl` to work. + +```yaml +spec: + configSecret: + : # for example `configSecret` + name: +``` + +### spec.dataSources + +`spec.dataSources` is an `optional` field that allows the user to provide a list of [VolumeSources](https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes) (i.e. secrets, configmaps, etc.) which will be mounted into the VaultServer pods. These volumes will be mounted into `/etc/vault/data/` directory. The first data will be named as `data-0`, the second one will be named as `data-1` and so on. + +```yaml +spec: + dataSources: + - secret: # mounted on /etc/vault/data/data-0 + secretName: custom-cert + - configMap: # mounted on /etc/vault/data/data-1 + name: special-config +``` + +### spec.monitor +`spec.monitor` is an optional field that is used to monitor the `vaultserver` instances. +```yaml +monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} +``` + +### spec.terminationPolicy +`spec.terminationPolicy` is an optional field that gives flexibility whether to nullify(reject) the delete operation of VaultServer crd or which resources KubeVault operator should keep or delete when you delete VaultServer crd. KubeVault provides following four termination policies: +- DoNotTerminate +- Halt +- Delete (Default) +- WipeOut + +When, `terminationPolicy` is `DoNotTerminate`, KubeVault takes advantage of ValidationWebhook feature in Kubernetes 1.9.0 or later clusters to provide safety from accidental deletion of VaultServer. If admission webhook is enabled, KubeVault prevents users from deleting the VaultServer as long as the spec.terminationPolicy is set to DoNotTerminate. + +### spec.backend + +`spec.backend` is a required field that specifies the Vault backend storage configuration. KubeVault operator generates storage configuration according to this `spec.backend`. + +```yaml +spec: + backend: + ... +``` +List of supported backends: + +- [Azure](/docs/v2025.11.21/concepts/vault-server-crds/storage/azure) +- [Consul](/docs/v2025.11.21/concepts/vault-server-crds/storage/consul) +- [DynamoDB](/docs/v2025.11.21/concepts/vault-server-crds/storage/dynamodb) +- [Etcd](/docs/v2025.11.21/concepts/vault-server-crds/storage/etcd) +- [GCS](/docs/v2025.11.21/concepts/vault-server-crds/storage/gcs) +- [In Memory](/docs/v2025.11.21/concepts/vault-server-crds/storage/inmem) +- [MySQL](/docs/v2025.11.21/concepts/vault-server-crds/storage/mysql) +- [PosgreSQL](/docs/v2025.11.21/concepts/vault-server-crds/storage/postgresql) +- [AWS S3](/docs/v2025.11.21/concepts/vault-server-crds/storage/s3) +- [Swift](/docs/v2025.11.21/concepts/vault-server-crds/storage/swift) +- [Filesystem](/docs/v2025.11.21/concepts/vault-server-crds/storage/filesystem) +- [Raft](/docs/v2025.11.21/concepts/vault-server-crds/storage/raft) + +#### spec.unsealer + +`spec.unsealer` is an optional field that specifies [Unsealer](https://github.com/kubevault/unsealer) configuration. Unsealer handles automatic initializing and unsealing of Vault. See [here](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/overview) for Unsealer documentation. + +```yaml +spec: + unsealer: + secretShares: + secretThresold: + retryPeriodSeconds: + overwriteExisting: + mode: + ... +``` + +#### spec.serviceTemplates + +You can also provide a list of templates for the services created by KubeVault operator for VaultServer through `spec.serviceTemplates`. This will allow you to set the type and other properties of the services. `spec.serviceTemplates` is an optional field. + +```yaml +spec: + serviceTemplates: + - alias: stats + spec: + type: ClusterIP +``` + +VaultServer allows following fields to be set in `spec.serviceTemplates`: + +- metadata: + - annotations (set as annotations on Vault service) +- spec: + - type + - ports + - clusterIP + - externalIPs + - loadBalancerIP + - loadBalancerSourceRanges + - externalTrafficPolicy + - healthCheckNodePort + - sessionAffinityConfig + +#### spec.podTemplate + +VaultServer allows providing a template for Vault pod through `spec.podTemplate`. KubeVault operator will pass the information provided in `spec.podTemplate` to the Deployment created for Vault. `spec.podTemplate` is an optional field. + +```yaml +spec: + podTemplate: + spec: + resources: + requests: + memory: "64Mi" + cpu: "250m" + limits: + memory: "128Mi" + cpu: "500m" +``` + +VaultServer accepts the following fields to set in `spec.podTemplate:` + +- metadata: + - annotations (set as annotations on Vault pods) +- controller: + - annotations (set as annotations on Vault statefulset) +- spec: + - resources + - imagePullSecrets + - nodeSelector + - affinity + - schedulerName + - tolerations + - priorityClassName + - priority + - securityContext + +You can find the full list of fields [here](https://github.com/kmodules/offshoot-api/blob/kubernetes-1.16.3/api/v1/types.go). Some of the fields of `spec.podTemplate` are described below: + +##### spec.podTemplate.spec.imagePullSecret + +`spec.podTemplate.spec.imagePullSecrets` is an optional field that points to secrets to be used for pulling docker images if you are using a private docker registry. + +##### spec.podTemplate.spec.nodeSelector + +`spec.podTemplate.spec.nodeSelector` is an optional field that specifies a map of key-value pairs. For the pod to be eligible to run on a node, the node must have each of the indicated key-value pairs as labels (it can have additional labels as well). To learn more, see [here](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) . + +##### spec.podTemplate.spec.resources + +`spec.podTemplate.spec.resources` is an optional field. This can be used to request compute resources required by Vault pods. To learn more, visit [here](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). + +#### spec.authMethods + +`spec.authMethods` is an optional field that specifies the list of auth methods to enable in Vault. + +```yaml +spec: + authMethods: + - type: kubernetes + path: k8s + - type: aws + path: aws +``` + +`spec.authMethods` has following fields: + +##### spec.authMethods[].type + +`spec.authMethods[].type` is a required field that specifies the name of the authentication method type. + +##### spec.authMethods[].path + +`spec.authMethods[].path` is a required field that specifies the path where to enable the auth method. + +##### spec.authMethods[].description + +`spec.authMethods[].description` is an optional field that specifies a human-friendly description of the auth method. + +##### spec.authMethods[].pluginName + +`spec.authMethods[].pluginName` is an optional field that specifies the name of the auth plugin to use based on the name in the plugin catalog. + +##### spec.authMethods[].local + +`spec.authMethods[].local` is an optional field that specifies if the auth method is local only. Local auth methods are not replicated nor (if a secondary) removed by replication. + +##### spec.authMethods[].config + +`spec.authMethods[].config` is an optional field that specifies configuration options for auth method. + +`spec.authMethods[].config` has following fields: + +- `defaultLeaseTTL` : `Optional`. Specifies the default lease duration. + +- `maxLeaseTTL` : `Optional`. Specifies the maximum lease duration. + +- `pluginName` : `Optional`. Specifies the name of the plugin in the plugin catalog to use. + +- `auditNonHMACRequestKeys` : `Optional`. Specifies the list of keys that will not be HMAC'd by audit devices in the request data object. + +- `auditNonHMACResponseKeys`: `Optional`. Specifies the list of keys that will not be HMAC'd by audit devices in the response data object. + +- `listingVisibility`: `Optional`. Specifies whether to show this is mount in the UI-specific listing endpoint. + +- `passthroughRequestHeaders`: `Optional`. Specifies a list of headers to whitelist and pass from the request to the backend. + +### VaultServer Status + +VaultServer Status shows the status of a Vault deployment. The status of the Vault is monitored and updated by the KubeVault operator. + +```yaml +status: + phase: +``` + +- `phase`: Indicates the phase Vault is currently in. Possible values of `status.phase`: + - Initializing + - Sealed + - Unsealing + - Critical + - NotReady + - Ready + +- `authMethodStatus` : Indicates the status of the auth methods specified in `spec.authMethods`. It has the following fields: + + - `type`: Specifies the name of the authentication method type + + - `path`: Specifies the path in which the auth method is enabled. + + - `status`: Specifies whether the auth method is enabled or not. + + - `reason`: Specifies the reason why failed to enable the auth method. diff --git a/content/docs/v2025.11.21/concepts/vault-server-crds/vaultserverversion.md b/content/docs/v2025.11.21/concepts/vault-server-crds/vaultserverversion.md new file mode 100644 index 000000000..89de83612 --- /dev/null +++ b/content/docs/v2025.11.21/concepts/vault-server-crds/vaultserverversion.md @@ -0,0 +1,101 @@ +--- +title: Vault Server Version | KubeVault Concepts +menu: + docs_v2025.11.21: + identifier: vaultserverversion-vault-server-crds + name: Vault Server Version + parent: vault-server-crds-concepts + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: concepts +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# VaultServerVersion + +## What is VaultServerVersion + +`VaultServerVersion` is a Kubernetes `Custom Resource Definitions` (CRD). It is a **non-namespaced** CRD. The name of this CRD will be used in `.spec.version` field of [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) CRD. It provides a way to specify the docker images for Vault, Unsealer, and Exporter. + +Using a separate CRD for specifying respective docker images allows us to modify the images independently of the KubeVault operator. This also allows users to use their custom images. + +```yaml +apiVersion: catalog.kubevault.com/v1alpha1 +kind: VaultServerVersion +metadata: + name: '1.10.3' +spec: + version: 1.10.3 + exporter: + image: kubevault/vault-exporter:v0.1.1 + unsealer: + image: kubevault/vault-unsealer:v0.8.0 + vault: + image: vault:1.10.3 +``` + +### VaultServerVersion Spec + +VaultServerVersion `.spec` contains image information. + +```yaml +apiVersion: catalog.kubevault.com/v1alpha1 +kind: VaultServerVersion +metadata: + name: '1.10.3' +spec: + version: 1.10.3 + exporter: + image: kubevault/vault-exporter:v0.1.1 + unsealer: + image: kubevault/vault-unsealer:v0.8.0 + vault: + image: vault:1.10.3 +``` + +`.spec` contains following fields: + +#### spec.version + +`spec.version` is a required field that specifies the original version of Vault that has been used to build the docker image specified in `spec.vault.image` field. + +#### spec.deprecated + +`spec.deprecated` is an optional field that specifies whether the specified docker images are supported by the current KubeVault operator. The default value of this field is false. + +#### spec.vault.image + +`spec.vault.image` is a required field that specifies the docker image which will be used for Vault. + +```yaml +spec: + vault: + image: vault:1.10.3 +``` + +#### spec.unsealer.image + +`spec.unsealer.image` is a required field that specifies the docker image which will be used for Unsealer. + +```yaml +spec: + unsealer: + image: kubevault/vault-unsealer:0.8.0 +``` + +#### spec.exporter.image + +`spec.exporter.image` is a required field that specifies the docker image which will be used to export Prometheus metrics. + +```yaml +spec: + exporter: + image: kubevault/vault-exporter:0.1.1 +``` diff --git a/content/docs/v2025.11.21/examples/guides/backup-restore/backup-configuration.yaml b/content/docs/v2025.11.21/examples/guides/backup-restore/backup-configuration.yaml new file mode 100644 index 000000000..f508d1a7e --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/backup-restore/backup-configuration.yaml @@ -0,0 +1,26 @@ +apiVersion: stash.appscode.com/v1beta1 +kind: BackupConfiguration +metadata: + name: demo-backup + namespace: demo +spec: + driver: Restic + repository: + name: gcp-demo-repo + namespace: demo + schedule: "*/5 * * * *" + timeOut: 2h + target: + ref: + apiVersion: appcatalog.appscode.com/v1alpha1 + kind: AppBinding + name: vault + runtimeSettings: + container: + securityContext: + runAsUser: 0 + runAsGroup: 0 + retentionPolicy: + name: 'keep-last-5' + keepLast: 5 + prune: true \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/backup-restore/repository.yaml b/content/docs/v2025.11.21/examples/guides/backup-restore/repository.yaml new file mode 100644 index 000000000..c53e45576 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/backup-restore/repository.yaml @@ -0,0 +1,15 @@ +apiVersion: stash.appscode.com/v1alpha1 +kind: Repository +metadata: + name: gcp-demo-repo + namespace: demo +spec: + backend: + gcs: + bucket: stash-testing + prefix: demo-vault + storageSecretName: gcs-secret + usagePolicy: + allowedNamespaces: + from: Same + wipeOut: false \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/backup-restore/restore-session.yaml b/content/docs/v2025.11.21/examples/guides/backup-restore/restore-session.yaml new file mode 100644 index 000000000..d2c0c62df --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/backup-restore/restore-session.yaml @@ -0,0 +1,20 @@ +apiVersion: stash.appscode.com/v1beta1 +kind: RestoreSession +metadata: + name: vault-restore-session + namespace: demo +spec: + repository: + name: gcp-demo-repo + target: + ref: + apiVersion: appcatalog.appscode.com/v1alpha1 + kind: AppBinding + name: vault + runtimeSettings: + container: + securityContext: + runAsUser: 0 + runAsGroup: 0 + rules: + - snapshots: [latest] \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/backup-restore/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/backup-restore/vaultserver.yaml new file mode 100644 index 000000000..0df7adf4b --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/backup-restore/vaultserver.yaml @@ -0,0 +1,30 @@ +apiVersion: kubevault.com/v1alpha2 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.10.3 + replicas: 3 + allowedSecretEngines: + namespaces: + from: All + backend: + raft: + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: WipeOut \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/policy-management/policy-reader-role.yaml b/content/docs/v2025.11.21/examples/guides/policy-management/policy-reader-role.yaml new file mode 100644 index 000000000..dab18a96d --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/policy-management/policy-reader-role.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: policy-reader-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: read-only-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "demo-sa" + serviceAccountNamespaces: + - "demo" diff --git a/content/docs/v2025.11.21/examples/guides/policy-management/read-only-policy.yaml b/content/docs/v2025.11.21/examples/guides/policy-management/read-only-policy.yaml new file mode 100644 index 000000000..558a7b112 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/policy-management/read-only-policy.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: read-only-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "sys/policy" { + capabilities = ["list"] + } + + path "sys/policy/*" { + capabilities = ["read"] + } \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/policy-management/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/policy-management/vaultserver.yaml new file mode 100644 index 000000000..51a469a47 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/policy-management/vaultserver.yaml @@ -0,0 +1,16 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + replicas: 1 + version: "1.2.3" + backend: + inmem: {} + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/policy-management/vaultserverversion.yaml b/content/docs/v2025.11.21/examples/guides/policy-management/vaultserverversion.yaml new file mode 100644 index 000000000..2d8274907 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/policy-management/vaultserverversion.yaml @@ -0,0 +1,13 @@ +apiVersion: catalog.kubevault.com/v1alpha1 +kind: VaultServerVersion +metadata: + name: 1.2.0 +spec: + version: 1.2.0 + deprecated: false + vault: + image: vault:1.2.0 + unsealer: + image: kubevault/vault-unsealer:v0.3.0 + exporter: + image: kubevault/vault-exporter:0.1.0 \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/provider/aks/my-vault.yaml b/content/docs/v2025.11.21/examples/guides/provider/aks/my-vault.yaml new file mode 100644 index 000000000..0314bad61 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/aks/my-vault.yaml @@ -0,0 +1,21 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: my-vault + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + azure: + container: demo-vault + accountName: vaultstorageac + accountKeySecret: azure-ac-key + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + azureKeyVault: + vaultBaseURL: https://vault-key-store.vault.azure.net/ + tenantID: aaaaaaa-bbbb-ccc-dddd-eeeeeeeee + aadClientSecret: azure-ad-client-secret diff --git a/content/docs/v2025.11.21/examples/guides/provider/aks/vaultserverversion.yaml b/content/docs/v2025.11.21/examples/guides/provider/aks/vaultserverversion.yaml new file mode 100644 index 000000000..2d8274907 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/aks/vaultserverversion.yaml @@ -0,0 +1,13 @@ +apiVersion: catalog.kubevault.com/v1alpha1 +kind: VaultServerVersion +metadata: + name: 1.2.0 +spec: + version: 1.2.0 + deprecated: false + vault: + image: vault:1.2.0 + unsealer: + image: kubevault/vault-unsealer:v0.3.0 + exporter: + image: kubevault/vault-exporter:0.1.0 \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/provider/eks/my-vault.yaml b/content/docs/v2025.11.21/examples/guides/provider/eks/my-vault.yaml new file mode 100644 index 000000000..40aac2f96 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/eks/my-vault.yaml @@ -0,0 +1,20 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: my-vault + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + s3: + bucket: "demo-vault-3" + region: "us-east-1" + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + awsKmsSsm: + region: "us-east-1" + kmsKeyID: "218daa5f-7173-429e-a030-288b30761f79" + ssmKeyPrefix: "/cluster/demo" diff --git a/content/docs/v2025.11.21/examples/guides/provider/external-vault/demo-policy.yaml b/content/docs/v2025.11.21/examples/guides/provider/external-vault/demo-policy.yaml new file mode 100644 index 000000000..99a2beac4 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/external-vault/demo-policy.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: demo-policy + namespace: demo +spec: + vaultRef: + name: vault-app + policyDocument: | + path "secret/*" { + capabilities = ["create", "read", "update", "delete", "list"] + } diff --git a/content/docs/v2025.11.21/examples/guides/provider/external-vault/policy-admin-sa.yaml b/content/docs/v2025.11.21/examples/guides/provider/external-vault/policy-admin-sa.yaml new file mode 100644 index 000000000..3ce5d5c95 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/external-vault/policy-admin-sa.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: policy-admin + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/provider/external-vault/policy-admin.hcl b/content/docs/v2025.11.21/examples/guides/provider/external-vault/policy-admin.hcl new file mode 100644 index 000000000..e34b487fd --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/external-vault/policy-admin.hcl @@ -0,0 +1,15 @@ +path "sys/policy/*" { + capabilities = ["create", "update", "read", "delete", "list"] +} + +path "sys/policy" { + capabilities = ["read", "list"] +} + +path "auth/kubernetes/role" { + capabilities = ["read", "list"] +} + +path "auth/kubernetes/role/*" { + capabilities = ["create", "update", "read", "delete", "list"] +} \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/provider/external-vault/token-review-binding.yaml b/content/docs/v2025.11.21/examples/guides/provider/external-vault/token-review-binding.yaml new file mode 100644 index 000000000..d54d58ea9 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/external-vault/token-review-binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: role-tokenreview-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: token-reviewer + namespace: demo \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/provider/external-vault/token-reviewer-sa.yaml b/content/docs/v2025.11.21/examples/guides/provider/external-vault/token-reviewer-sa.yaml new file mode 100644 index 000000000..70c550d43 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/external-vault/token-reviewer-sa.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: token-reviewer + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/provider/external-vault/vault-app.yaml b/content/docs/v2025.11.21/examples/guides/provider/external-vault/vault-app.yaml new file mode 100644 index 000000000..65c04eebb --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/external-vault/vault-app.yaml @@ -0,0 +1,15 @@ +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + clientConfig: + url: http://vault.default.svc:8200 + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: kubernetes + vaultRole: policy-admin-role + kubernetes: + serviceAccountName: policy-admin diff --git a/content/docs/v2025.11.21/examples/guides/provider/external-vault/vault.yaml b/content/docs/v2025.11.21/examples/guides/provider/external-vault/vault.yaml new file mode 100644 index 000000000..26a0b043e --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/external-vault/vault.yaml @@ -0,0 +1,46 @@ +apiVersion: v1 +kind: Service +metadata: + name: vault + namespace: default +spec: + ports: + - name: http + nodePort: 30001 + port: 8200 + selector: + app: vault + type: NodePort +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: vault + namespace: default + labels: + app: vault +spec: + serviceName: "vault" + selector: + matchLabels: + app: vault + replicas: 1 + template: + metadata: + labels: + app: vault + spec: + containers: + - name: vault + image: "vault:1.0.0" + args: + - "server" + - "-dev" + - "-dev-root-token-id=aajf-dhg-ddht-ccdf" + ports: + - name: http + containerPort: 8200 + protocol: "TCP" + - name: server + containerPort: 8201 + protocol: "TCP" diff --git a/content/docs/v2025.11.21/examples/guides/provider/gke/my-vault.yaml b/content/docs/v2025.11.21/examples/guides/provider/gke/my-vault.yaml new file mode 100644 index 000000000..ea784577a --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/gke/my-vault.yaml @@ -0,0 +1,23 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: my-vault + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + gcs: + bucket: "demo-vault" + credentialSecret: "google-cred" + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + googleKmsGcs: + bucket: "demo-vault" + kmsProject: "ackube" + kmsLocation: "global" + kmsKeyRing: "vault" + kmsCryptoKey: "vault-key" + credentialSecret: "google-cred" diff --git a/content/docs/v2025.11.21/examples/guides/provider/gke/vaultserverversion.yaml b/content/docs/v2025.11.21/examples/guides/provider/gke/vaultserverversion.yaml new file mode 100644 index 000000000..31e040a82 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/gke/vaultserverversion.yaml @@ -0,0 +1,12 @@ +apiVersion: catalog.kubevault.com/v1alpha1 +kind: VaultServerVersion +metadata: + name: 1.2.0 +spec: + exporter: + image: kubevault/vault-exporter:v0.1.0 + unsealer: + image: kubevault/vault-unsealer:v0.3.0 + vault: + image: vault:1.2.0 + version: 1.2.0 diff --git a/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/demo-policy-secret-admin.yaml b/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/demo-policy-secret-admin.yaml new file mode 100644 index 000000000..26767164a --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/demo-policy-secret-admin.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: demo-policy-secret-admin + namespace: demo +spec: + vaultRef: + name: my-vault + policyDocument: | + path "secret/*" { + capabilities = ["create", "read", "update", "delete", "list"] + } diff --git a/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/demo-policy-secret-reader.yaml b/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/demo-policy-secret-reader.yaml new file mode 100644 index 000000000..198b37de8 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/demo-policy-secret-reader.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: demo-policy-secret-reader + namespace: demo +spec: + vaultRef: + name: vault-app + policyDocument: | + path "secret/*" { + capabilities = ["read", "list"] + } diff --git a/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/my-vault.yaml b/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/my-vault.yaml new file mode 100644 index 000000000..9977751b2 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/my-vault.yaml @@ -0,0 +1,34 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: my-vault + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + gcs: + bucket: "demo-vault" + credentialSecret: "google-cred" + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: LoadBalancer + loadBalancerIP: 104.155.177.205 + tls: + certificates: + - alias: ca + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + googleKmsGcs: + bucket: "demo-vault" + kmsProject: "ackube" + kmsLocation: "global" + kmsKeyRing: "vault" + kmsCryptoKey: "vault-key" + credentialSecret: "google-cred" diff --git a/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/vault-app.yaml b/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/vault-app.yaml new file mode 100644 index 000000000..a6a8e814e --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/vault-app.yaml @@ -0,0 +1,11 @@ +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + secret: + name: vault-token + clientConfig: + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9UQXhNRGN3T1RNNE1UaGFGdzB5T1RBeE1EUXdPVE00TVRoYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdXZxWFJrMGZrMHNWMFpoMDQwd0FaVTBhCkhlRW9vUnlVMlpaaGtjS3dPS201N2pUWkJaMEkvMjg2dTNpUVFpc2tMTFNjYUtvaHp0c012RXFCU0JpNU5MNEMKVXVQbm5CZklIVVo1UDhwQWNOUXJ5SURETGxXZTFBTEVKU0N0L3daRG5mMkRPdXZGSVMybFJVZDV2WFp1dlVjWgptdml5T3VUOW9CclNwNkh5YUpRYkUrZk1qQTRvZ0ZoQWZmN1djMm1DVk1jam8wU3htK2lrVWxVZWhXdWd4T3M0Cm5GUG5pWmt3a1h0KzFweU45WjltclhwUTlZM3FvdGlmdk1aUnVhVS9hbjUxOUZqSWdzVUZtRGVoZ3c3blJwYkkKZ0NGeUNPSlc5ZTNDczNRVTViVTJYUk1leDBlTDZReTZJY2dDdGZIRmpBeGhjUHAzeEJjRW5XSEdONDM2dHdJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFUMzFuQUNpMmNySW0rWCtGZUNocjJJcnhZeGFDSlpLNW92Y1Jqem5TZFR0N2JadWoKcTVZQW5jbitESDlxUURkczFVTEdjR1ZISlpiS3RORU9GVVlJbDVXYUZBVnNBMTJoaURCZnJXc24ydUV6K0pUVwovcStLSVE0OW1LUWV1TG80bkVoQnRJYjJzaXBKMmxmUEVyUXhHQllrZ3lOT05zOTN5NEdPVXU4dVdBaUFqZ21oCmM4a1QzTVV0ZVRNUHczQ3JKU2ZtbGUxQkk0bkNPNXEreW54Zk56SXZqZU5PYnNvVTdOOVhoZTdCQjZSSzQ1akgKVW41bzBTZkkrR0dYU0l5eWFxVHlJRUJkK3Nub1pMRWQzMm9DeWJFOC9QajE3T3BDZHhhd0ZnZWJGUnNEQ2pkRQo0bUI2RmVPMi9md3VFUk5lTlZnczBHMjBPc2t4cDJoTWJRYUlJZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + url: https://104.155.177.205:8200 diff --git a/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/vault-token.yaml b/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/vault-token.yaml new file mode 100644 index 000000000..f17c211f0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/vault-token.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +data: + token: cy43RERVOWp5UnhSN05kck1FUzBDNkNaTUs= +kind: Secret +metadata: + name: vault-token + namespace: demo +type: kubevault.com/token \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/vaultserverversion.yaml b/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/vaultserverversion.yaml new file mode 100644 index 000000000..31e040a82 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/provider/multi-cluster/vaultserverversion.yaml @@ -0,0 +1,12 @@ +apiVersion: catalog.kubevault.com/v1alpha1 +kind: VaultServerVersion +metadata: + name: 1.2.0 +spec: + exporter: + image: kubevault/vault-exporter:v0.1.0 + unsealer: + image: kubevault/vault-unsealer:v0.3.0 + vault: + image: vault:1.2.0 + version: 1.2.0 diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/aws/pod.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/pod.yaml new file mode 100644 index 000000000..0719ba2c8 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/pod.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/aws-keys" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/aws/policy.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/policy.yaml new file mode 100644 index 000000000..dd203e63d --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/policy.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: aws-reader-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "your-aws-path/creds/*" { + capabilities = ["read", "create"] + } diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/aws/policybinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/policybinding.yaml new file mode 100644 index 000000000..de5954891 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/policybinding.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: aws-reader-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: aws-reader-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "test-user-account" + serviceAccountNamespaces: + - "demo" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secret-role-binding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secret-role-binding.yaml new file mode 100644 index 000000000..e5eb70596 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secret-role-binding.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: AWSRole + name: aws-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secret.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secret.yaml new file mode 100644 index 000000000..b7b3292b0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: aws-cred + namespace: demo +data: + access_key: N2I2bl== + secret_key: N2I2bl== diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secretengine.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secretengine.yaml new file mode 100644 index 000000000..ab5dd722f --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secretengine.yaml @@ -0,0 +1,14 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: aws-secret-engine + namespace: demo +spec: + vaultRef: + name: vault + aws: + credentialSecret: aws-cred + region: us-east-1 + leaseConfig: + lease: 1h + leaseMax: 1h \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secretenginerole.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secretenginerole.yaml new file mode 100644 index 000000000..7556f1769 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secretenginerole.yaml @@ -0,0 +1,20 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: AWSRole +metadata: + name: aws-role + namespace: demo +spec: + secretEngineRef: + name: aws-secret-engine + credentialType: iam_user + policyDocument: | + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "ec2:*", + "Resource": "*" + } + ] + } diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secretproviderclass.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secretproviderclass.yaml new file mode 100644 index 000000000..4d777b9b5 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/secretproviderclass.yaml @@ -0,0 +1,17 @@ +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.aws-reader-role" + objects: | + - objectName: "access_key" + secretPath: "your-aws-path/creds/k8s.-.demo.aws-role" + secretKey: "access_key" + - objectName: "secret_key" + secretPath: "your-aws-path/creds/k8s.-.demo.aws-role" + secretKey: "secret_key" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/aws/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/serviceaccount.yaml new file mode 100644 index 000000000..784a86322 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/aws/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/vaultserver.yaml new file mode 100644 index 000000000..1017c6396 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/aws/vaultserver.yaml @@ -0,0 +1,38 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.7.3 + replicas: 3 + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/azure/pod.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/pod.yaml new file mode 100644 index 000000000..a23159131 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/pod.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/azure-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/azure/policy.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/policy.yaml new file mode 100644 index 000000000..b132d7aa1 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/policy.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: azure-reader-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "your-azure-path/creds/*" { + capabilities = ["read", "create"] + } \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/azure/policybinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/policybinding.yaml new file mode 100644 index 000000000..34af73767 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/policybinding.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: azure-reader-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: azure-reader-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "test-user-account" + serviceAccountNamespaces: + - "demo" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secret-role-binding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secret-role-binding.yaml new file mode 100644 index 000000000..5714de4b9 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secret-role-binding.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: AzureRole + name: azure-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secret.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secret.yaml new file mode 100644 index 000000000..1868432bc --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secret.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +metadata: + name: azure-cred + namespace: demo +data: + client-secret: eyJtc2ciOiJleGFtcGxlIn0= + subscription-id: eyJtc2ciOiJleGFtcGxlIn0= + client-id: eyJtc2ciOiJleGFtcGxlIn0= + tenant-id: eyJtc2ciOiJleGFtcGxlIn0= \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secretengine.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secretengine.yaml new file mode 100644 index 000000000..bd0d22c01 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secretengine.yaml @@ -0,0 +1,10 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: azure-engine + namespace: demo +spec: + vaultRef: + name: vault + azure: + credentialSecret: azure-cred diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secretenginerole.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secretenginerole.yaml new file mode 100644 index 000000000..b0dd281ce --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secretenginerole.yaml @@ -0,0 +1,10 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: AzureRole +metadata: + name: azure-role + namespace: demo +spec: + secretEngineRef: + name: azure-secret-engine + applicationObjectID: e211afbc-cc4a-462f-ad6f-59e26eb5406f + ttl: 1h diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secretproviderclass.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secretproviderclass.yaml new file mode 100644 index 000000000..668b616c8 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/secretproviderclass.yaml @@ -0,0 +1,17 @@ +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.azure-reader-role" + objects: | + - objectName: "client_id" + secretPath: "your-azure-path/creds/k8s.-.demo.azure-role" + secretKey: "client_id" + - objectName: "client_secret" + secretPath: "your-azure-path/creds/k8s.-.demo.azure-role" + secretKey: "client_secret" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/azure/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/serviceaccount.yaml new file mode 100644 index 000000000..784a86322 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/azure/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/vaultserver.yaml new file mode 100644 index 000000000..52d6a78a0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/azure/vaultserver.yaml @@ -0,0 +1,38 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.7.3 + replicas: 3 + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/elasticsearch.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/elasticsearch.yaml new file mode 100644 index 000000000..026877448 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/elasticsearch.yaml @@ -0,0 +1,18 @@ +apiVersion: kubedb.com/v1alpha2 +kind: Elasticsearch +metadata: + name: elasticsearch + namespace: demo +spec: + version: xpack-7.17.15 + enableSSL: false + replicas: 3 + storageType: Durable + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + terminationPolicy: DoNotTerminate \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/pod.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/pod.yaml new file mode 100644 index 000000000..6d292635a --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/pod.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/es-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/policy.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/policy.yaml new file mode 100644 index 000000000..ba9b4cfcf --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/policy.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: es-reader-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "your-database-path/creds/*" { + capabilities = ["read"] + } \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/policybinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/policybinding.yaml new file mode 100644 index 000000000..0f6ad90f0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/policybinding.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: es-reader-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: es-reader-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "test-user-account" + serviceAccountNamespaces: + - "demo" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secret-role-binding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secret-role-binding.yaml new file mode 100644 index 000000000..0ea676466 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secret-role-binding.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: ElasticsearchRole + name: es-superuser-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secretengine.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secretengine.yaml new file mode 100644 index 000000000..76f2283b3 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secretengine.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: es-engine + namespace: demo +spec: + vaultRef: + name: vault + elasticsearch: + databaseRef: + name: elasticsearch + namespace: demo + pluginName: "elasticsearch-database-plugin" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secretenginerole.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secretenginerole.yaml new file mode 100644 index 000000000..c3bc2658b --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secretenginerole.yaml @@ -0,0 +1,12 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: ElasticsearchRole +metadata: + name: es-superuser-role + namespace: demo +spec: + secretEngineRef: + name: es-secret-engine + creationStatements: + - '{"elasticsearch_roles": ["superuser"]}' + defaultTTL: 1h + maxTTL: 24h diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secretproviderclass.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secretproviderclass.yaml new file mode 100644 index 000000000..f9faecee6 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/secretproviderclass.yaml @@ -0,0 +1,17 @@ +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.es-reader-role" + objects: | + - objectName: "es-creds-username" + secretPath: "your-database-path/creds/k8s.-.demo.es-superuser-role" + secretKey: "username" + - objectName: "es-creds-password" + secretPath: "your-database-path/creds/k8s.-.demo.es-superuser-role" + secretKey: "password" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/serviceaccount.yaml new file mode 100644 index 000000000..ed79c6d5b --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/vaultserver.yaml new file mode 100644 index 000000000..52d6a78a0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch/vaultserver.yaml @@ -0,0 +1,38 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.7.3 + replicas: 3 + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/pod.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/pod.yaml new file mode 100644 index 000000000..53b75cfcc --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/pod.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/gcp-access-token" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/policy.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/policy.yaml new file mode 100644 index 000000000..4a575a19e --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/policy.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: gcp-reader-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "your-gcp-path/token/*" { + capabilities = ["read"] + } \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/policybinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/policybinding.yaml new file mode 100644 index 000000000..ce9e22ad0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/policybinding.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: gcp-reader-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: gcp-reader-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "test-user-account" + serviceAccountNamespaces: + - "demo" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secret-role-binding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secret-role-binding.yaml new file mode 100644 index 000000000..fed6617a5 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secret-role-binding.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: GCPRole + name: gcp-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secret.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secret.yaml new file mode 100644 index 000000000..cf78f5f5e --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secret.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: gcp-cred + namespace: demo +data: + sa.json: eyJtc2ciOiJleGFtcGxlIn0= ## base64 encoded google service account credential \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secretengine.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secretengine.yaml new file mode 100644 index 000000000..8d949a29c --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secretengine.yaml @@ -0,0 +1,10 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: gcp-engine + namespace: demo +spec: + vaultRef: + name: vault + gcp: + credentialSecret: gcp-cred diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secretenginerole.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secretenginerole.yaml new file mode 100644 index 000000000..d2bf01aa2 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secretenginerole.yaml @@ -0,0 +1,16 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: GCPRole +metadata: + name: gcp-role + namespace: demo +spec: + secretEngineRef: + name: gcp-secret-engine + secretType: "access_token" + project: appscode-testing + bindings: | + resource "//cloudresourcemanager.googleapis.com/projects/appscode-testing" { + roles = ["roles/viewer"] + } + tokenScopes: + - https://www.googleapis.com/auth/cloud-platform \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secretproviderclass.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secretproviderclass.yaml new file mode 100644 index 000000000..4e6cf2b1e --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/secretproviderclass.yaml @@ -0,0 +1,14 @@ +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.gcp-reader-role" + objects: | + - objectName: "gcp-token" + secretPath: "your-gcp-path/token/k8s.-.demo.gcp-role" + secretKey: "token" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/serviceaccount.yaml new file mode 100644 index 000000000..784a86322 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/vaultserver.yaml new file mode 100644 index 000000000..1017c6396 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/gcp/vaultserver.yaml @@ -0,0 +1,38 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.7.3 + replicas: 3 + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/kv/pod.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/kv/pod.yaml new file mode 100644 index 000000000..da6c9a14f --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/kv/pod.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Pod +metadata: + name: test-app + namespace: demo +spec: + serviceAccountName: pod-sa + containers: + - image: jweissig/app:0.0.1 + name: test-app + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/test" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-database" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/kv/policy.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/kv/policy.yaml new file mode 100644 index 000000000..a1fb2f434 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/kv/policy.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: kv-se-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "secret/*" { + capabilities = ["read"] + } diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/kv/policybinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/kv/policybinding.yaml new file mode 100644 index 000000000..111996f74 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/kv/policybinding.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: kv-se-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: kv-se-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "pod-sa" + serviceAccountNamespaces: + - "demo" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/kv/secretproviderclass.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/kv/secretproviderclass.yaml new file mode 100644 index 000000000..1e6ee18d3 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/kv/secretproviderclass.yaml @@ -0,0 +1,14 @@ +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-database + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.kv-se-role" + objects: | + - objectName: "db-password" + secretPath: "secret/db-pass" + secretKey: "password" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/kv/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/kv/serviceaccount.yaml new file mode 100644 index 000000000..3eef7fb34 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/kv/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pod-sa + namespace: demo \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/kv/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/kv/vaultserver.yaml new file mode 100644 index 000000000..52d6a78a0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/kv/vaultserver.yaml @@ -0,0 +1,38 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.7.3 + replicas: 3 + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/mariadb.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/mariadb.yaml new file mode 100644 index 000000000..0aa7b7c91 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/mariadb.yaml @@ -0,0 +1,16 @@ +apiVersion: kubedb.com/v1alpha2 +kind: MariaDB +metadata: + name: mariadb + namespace: demo +spec: + version: 10.6.16 + storageType: Durable + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + terminationPolicy: DoNotTerminate diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/pod.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/pod.yaml new file mode 100644 index 000000000..d5676e694 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/pod.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/mysql-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/policy.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/policy.yaml new file mode 100644 index 000000000..7bec72f34 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/policy.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: mariadb-reader-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "your-database-path/creds/*" { + capabilities = ["read"] + } diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/policybinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/policybinding.yaml new file mode 100644 index 000000000..fc71fd5e9 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/policybinding.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: mariadb-reader-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: mariadb-reader-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "test-user-account" + serviceAccountNamespaces: + - "demo" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secret-role-binding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secret-role-binding.yaml new file mode 100644 index 000000000..3aac38ece --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secret-role-binding.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: MariaDBRole + name: mariadb-superuser-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secretengine.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secretengine.yaml new file mode 100644 index 000000000..afa0ea361 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secretengine.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: mariadb-engine + namespace: demo +spec: + vaultRef: + name: vault + mysql: + databaseRef: + name: mariadb + namespace: demo + pluginName: "mysql-database-plugin" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secretenginerole.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secretenginerole.yaml new file mode 100644 index 000000000..36137d83a --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secretenginerole.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: MariaDBRole +metadata: + name: mariadb-superuser-role + namespace: demo +spec: + secretEngineRef: + name: mariadb-secret-engine + creationStatements: + - "CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';" + - "GRANT SELECT ON *.* TO '{{name}}'@'%';" + defaultTTL: 1h + maxTTL: 24h diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secretproviderclass.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secretproviderclass.yaml new file mode 100644 index 000000000..a78c11390 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/secretproviderclass.yaml @@ -0,0 +1,17 @@ +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.mysql-reader-role" + objects: | + - objectName: "mariadb-creds-username" + secretPath: "your-database-path/creds/k8s.-.demo.mariadb-superuser-role" + secretKey: "username" + - objectName: "mariadb-creds-password" + secretPath: "your-database-path/creds/k8s.-.demo.mariadb-superuser-role" + secretKey: "password" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/serviceaccount.yaml new file mode 100644 index 000000000..ed79c6d5b --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/vaultserver.yaml new file mode 100644 index 000000000..52d6a78a0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mariadb/vaultserver.yaml @@ -0,0 +1,38 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.7.3 + replicas: 3 + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/mongodb.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/mongodb.yaml new file mode 100644 index 000000000..05208afc7 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/mongodb.yaml @@ -0,0 +1,16 @@ +apiVersion: kubedb.com/v1alpha2 +kind: MongoDB +metadata: + name: mongodb + namespace: demo +spec: + version: "4.4.26" + storageType: Durable + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + terminationPolicy: DoNotTerminate diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/pod.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/pod.yaml new file mode 100644 index 000000000..0df264719 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/pod.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/mongo-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/policy.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/policy.yaml new file mode 100644 index 000000000..5fdf0f937 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/policy.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: mongo-reader-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "your-database-path/creds/*" { + capabilities = ["read"] + } diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/policybinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/policybinding.yaml new file mode 100644 index 000000000..904dd1247 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/policybinding.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: mongo-reader-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: mongo-reader-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "test-user-account" + serviceAccountNamespaces: + - "demo" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretengine.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretengine.yaml new file mode 100644 index 000000000..7405c5db0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretengine.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: mongo-engine + namespace: demo +spec: + vaultRef: + name: vault + mongodb: + databaseRef: + name: mongodb + namespace: demo + pluginName: "mongodb-database-plugin" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretenginerole.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretenginerole.yaml new file mode 100644 index 000000000..5133d7669 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretenginerole.yaml @@ -0,0 +1,12 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: MongoDBRole +metadata: + name: mongo-superuser-role + namespace: demo +spec: + secretEngineRef: + name: mongo-secret-engine + creationStatements: + - "{ \"db\": \"admin\", \"roles\": [{ \"role\": \"readWrite\" }, {\"role\": \"read\", \"db\": \"foo\"}] }" + defaultTTL: 1h + maxTTL: 24h \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretproviderclass.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretproviderclass.yaml new file mode 100644 index 000000000..3f5c432fe --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretproviderclass.yaml @@ -0,0 +1,17 @@ +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.mongo-reader-role" + objects: | + - objectName: "mongo-creds-username" + secretPath: "your-database-path/creds/k8s.-.demo.mongo-superuser-role" + secretKey: "username" + - objectName: "mongo-creds-password" + secretPath: "your-database-path/creds/k8s.-.demo.mongo-superuser-role" + secretKey: "password" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretrolebinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretrolebinding.yaml new file mode 100644 index 000000000..bd727cd2d --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/secretrolebinding.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: MongoDBRole + name: mongo-superuser-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/serviceaccount.yaml new file mode 100644 index 000000000..ed79c6d5b --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/vaultserver.yaml new file mode 100644 index 000000000..52d6a78a0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mongodb/vaultserver.yaml @@ -0,0 +1,38 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.7.3 + replicas: 3 + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/mysql.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/mysql.yaml new file mode 100644 index 000000000..fb71010f2 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/mysql.yaml @@ -0,0 +1,16 @@ +apiVersion: kubedb.com/v1alpha2 +kind: MySQL +metadata: + name: mysql + namespace: demo +spec: + version: "8.0.36" + storageType: Durable + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + terminationPolicy: DoNotTerminate diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/pod.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/pod.yaml new file mode 100644 index 000000000..d5676e694 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/pod.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/mysql-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/policy.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/policy.yaml new file mode 100644 index 000000000..a36abbcfd --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/policy.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: mysql-reader-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "your-database-path/creds/*" { + capabilities = ["read"] + } diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/policybinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/policybinding.yaml new file mode 100644 index 000000000..84f072981 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/policybinding.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: mysql-reader-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: mysql-reader-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "test-user-account" + serviceAccountNamespaces: + - "demo" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secret-role-binding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secret-role-binding.yaml new file mode 100644 index 000000000..5e633f311 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secret-role-binding.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: MySQLRole + name: mysql-superuser-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secretengine.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secretengine.yaml new file mode 100644 index 000000000..4d632e92e --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secretengine.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: mysql-engine + namespace: demo +spec: + vaultRef: + name: vault + mysql: + databaseRef: + name: mysql + namespace: demo + pluginName: "mysql-database-plugin" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secretenginerole.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secretenginerole.yaml new file mode 100644 index 000000000..211cddf9b --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secretenginerole.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: MySQLRole +metadata: + name: mysql-superuser-role + namespace: demo +spec: + secretEngineRef: + name: sql-secret-engine + creationStatements: + - "CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';" + - "GRANT SELECT ON *.* TO '{{name}}'@'%';" + defaultTTL: 1h + maxTTL: 24h diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secretproviderclass.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secretproviderclass.yaml new file mode 100644 index 000000000..f64c7cf16 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/secretproviderclass.yaml @@ -0,0 +1,17 @@ +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.mysql-reader-role" + objects: | + - objectName: "mysql-creds-username" + secretPath: "your-database-path/creds/k8s.-.demo.mysql-superuser-role" + secretKey: "username" + - objectName: "mysql-creds-password" + secretPath: "your-database-path/creds/k8s.-.demo.mysql-superuser-role" + secretKey: "password" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/serviceaccount.yaml new file mode 100644 index 000000000..ed79c6d5b --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/vaultserver.yaml new file mode 100644 index 000000000..52d6a78a0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/mysql/vaultserver.yaml @@ -0,0 +1,38 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.7.3 + replicas: 3 + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/pki/pod.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/pki/pod.yaml new file mode 100644 index 000000000..29ce4ecfa --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/pki/pod.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/pki-assets" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/pki/policy.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/pki/policy.yaml new file mode 100644 index 000000000..5335bc323 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/pki/policy.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: pki-se-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "pki/issue/*" { + capabilities = ["update"] + } diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/pki/policybinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/pki/policybinding.yaml new file mode 100644 index 000000000..061d8cbe4 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/pki/policybinding.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: pki-se-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: pki-se-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "test-user-account" + serviceAccountNamespaces: + - "demo" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/pki/secretproviderclass.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/pki/secretproviderclass.yaml new file mode 100644 index 000000000..179bbbb6b --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/pki/secretproviderclass.yaml @@ -0,0 +1,42 @@ +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.pki-se-role" + objects: | + - objectName: "certificate" + secretPath: "pki/issue/example-dot-com" + secretKey: "certificate" + secretArgs: + common_name: "www.my-website.com" + ttl: 24h + method: "POST" + + - objectName: "issuing_ca" + secretPath: "pki/issue/example-dot-com" + secretKey: "issuing_ca" + secretArgs: + common_name: "www.my-website.com" + ttl: 24h + method: "POST" + + - objectName: "private_key" + secretPath: "pki/issue/example-dot-com" + secretKey: "private_key" + secretArgs: + common_name: "www.my-website.com" + ttl: 24h + method: "POST" + + - objectName: "private_key_type" + secretPath: "pki/issue/example-dot-com" + secretKey: "private_key_type" + secretArgs: + common_name: "www.my-website.com" + ttl: 24h + method: "POST" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/pki/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/pki/serviceaccount.yaml new file mode 100644 index 000000000..784a86322 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/pki/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/pki/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/pki/vaultserver.yaml new file mode 100644 index 000000000..1017c6396 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/pki/vaultserver.yaml @@ -0,0 +1,38 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.7.3 + replicas: 3 + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/pod.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/pod.yaml new file mode 100644 index 000000000..924a4e60f --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/pod.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/postgres-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/policy.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/policy.yaml new file mode 100644 index 000000000..ad3134891 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/policy.yaml @@ -0,0 +1,12 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: postgres-reader-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "your-database-path/creds/*" { + capabilities = ["read"] + } \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/policybinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/policybinding.yaml new file mode 100644 index 000000000..ce3734e04 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/policybinding.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: postgres-reader-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: postgres-reader-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "test-user-account" + serviceAccountNamespaces: + - "demo" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/postgres.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/postgres.yaml new file mode 100644 index 000000000..d6283e849 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/postgres.yaml @@ -0,0 +1,16 @@ +apiVersion: kubedb.com/v1alpha2 +kind: Postgres +metadata: + name: postgres + namespace: demo +spec: + version: "13.13" + storageType: Durable + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + terminationPolicy: DoNotTerminate diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretengine.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretengine.yaml new file mode 100644 index 000000000..d55e5aab4 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretengine.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: postgres-engine + namespace: demo +spec: + vaultRef: + name: vault + mysql: + databaseRef: + name: postgres + namespace: demo + pluginName: "postgresql-database-plugin" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretenginerole.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretenginerole.yaml new file mode 100644 index 000000000..0fe69726b --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretenginerole.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: PostgresRole +metadata: + name: postgres-superuser-role + namespace: demo +spec: + secretEngineRef: + name: pg-secret-engine + creationStatements: + - "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';" + - "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" + defaultTTL: 1h + maxTTL: 24h diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretproviderclass.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretproviderclass.yaml new file mode 100644 index 000000000..f1139c413 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretproviderclass.yaml @@ -0,0 +1,17 @@ +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.postgres-reader-role" + objects: | + - objectName: "postgres-creds-username" + secretPath: "your-database-path/creds/k8s.-.demo.postgres-superuser-role" + secretKey: "username" + - objectName: "postgres-creds-password" + secretPath: "your-database-path/creds/k8s.-.demo.postgres-superuser-role" + secretKey: "password" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretrolebinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretrolebinding.yaml new file mode 100644 index 000000000..9805cf1c0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/secretrolebinding.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: PostgresRole + name: postgres-superuser-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/serviceaccount.yaml new file mode 100644 index 000000000..ed79c6d5b --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/vaultserver.yaml new file mode 100644 index 000000000..52d6a78a0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/postgres/vaultserver.yaml @@ -0,0 +1,38 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.7.3 + replicas: 3 + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/redis/pod.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/pod.yaml new file mode 100644 index 000000000..ec1bf8b27 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/pod.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/redis-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/redis/redis.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/redis.yaml new file mode 100644 index 000000000..ff388aa45 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/redis.yaml @@ -0,0 +1,17 @@ +apiVersion: kubedb.com/v1alpha2 +kind: Redis +metadata: + name: redis-standalone + namespace: demo +spec: + version: 6.2.14 + storageType: Durable + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + terminationPolicy: WipeOut + diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/redis/redisaccessrequest.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/redisaccessrequest.yaml new file mode 100644 index 000000000..dc742d667 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/redisaccessrequest.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: write-read-access-req + namespace: demo +spec: + roleRef: + kind: RedisRole + name: write-read-role + subjects: + - kind: ServiceAccount + name: write-read-user + namespace: demo \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/redis/secret-role-binding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/secret-role-binding.yaml new file mode 100644 index 000000000..5faf5849e --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/secret-role-binding.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: RedisRole + name: write-read-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo⏎ \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/redis/secretengine.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/secretengine.yaml new file mode 100644 index 000000000..aef131581 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/secretengine.yaml @@ -0,0 +1,14 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: redis-secret-engine + namespace: demo +spec: + vaultRef: + name: vault + namespace: demo + redis: + databaseRef: + name: redis-standalone + namespace: demo + pluginName: "redis-database-plugin" diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/redis/secretenginerole.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/secretenginerole.yaml new file mode 100644 index 000000000..5b4ceafc0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/secretenginerole.yaml @@ -0,0 +1,12 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: RedisRole +metadata: + name: write-read-role + namespace: demo +spec: + secretEngineRef: + name: redis-secret-engine + creationStatements: + - '["~*", "+@read","+@write"]' + defaultTTL: 1h + maxTTL: 24h diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/redis/secretproviderclass.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/secretproviderclass.yaml new file mode 100644 index 000000000..7b60133fe --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/secretproviderclass.yaml @@ -0,0 +1,19 @@ +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: k8s.kubevault.com.demo.srb-demo-secret-role-binding + objects: | + - objectName: "redis-creds-username" + secretPath: "/k8s.kubevault.com.redis.demo.redis-secret-engine/creds/k8s.kubevault.com.demo.write-read-role" + #secretPath: "your-database-path/creds/your-role-name" + secretKey: "username" + - objectName: "redis-creds-password" + secretPath: "/k8s.kubevault.com.redis.demo.redis-secret-engine/creds/k8s.kubevault.com.demo.write-read-role" + #secretPath: "your-database-path/creds/your-role-name" + secretKey: "password" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/redis/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/serviceaccount.yaml new file mode 100644 index 000000000..ed79c6d5b --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/redis/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/vaultserver.yaml new file mode 100644 index 000000000..8f8979e5e --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/redis/vaultserver.yaml @@ -0,0 +1,27 @@ +apiVersion: kubevault.com/v1alpha2 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + replicas: 3 + version: 1.10.3 + allowedSecretEngines: + namespaces: + from: All + secretEngines: + - redis + backend: + raft: + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + terminationPolicy: WipeOut diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secret.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secret.yaml new file mode 100644 index 000000000..b7b3292b0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: aws-cred + namespace: demo +data: + access_key: N2I2bl== + secret_key: N2I2bl== diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secretaccessrequest.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secretaccessrequest.yaml new file mode 100644 index 000000000..a354e378c --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secretaccessrequest.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: aws-cred-req + namespace: dev +spec: + roleRef: + kind: AWSRole + name: aws-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: test diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secretengine.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secretengine.yaml new file mode 100644 index 000000000..ab5dd722f --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secretengine.yaml @@ -0,0 +1,14 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: aws-secret-engine + namespace: demo +spec: + vaultRef: + name: vault + aws: + credentialSecret: aws-cred + region: us-east-1 + leaseConfig: + lease: 1h + leaseMax: 1h \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secretenginerole.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secretenginerole.yaml new file mode 100644 index 000000000..7556f1769 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/secretenginerole.yaml @@ -0,0 +1,20 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: AWSRole +metadata: + name: aws-role + namespace: demo +spec: + secretEngineRef: + name: aws-secret-engine + credentialType: iam_user + policyDocument: | + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "ec2:*", + "Resource": "*" + } + ] + } diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/serviceaccount.yaml new file mode 100644 index 000000000..66bac1f05 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: test \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/vaultserver.yaml new file mode 100644 index 000000000..1017c6396 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-access-request/vaultserver.yaml @@ -0,0 +1,38 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.7.3 + replicas: 3 + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secret.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secret.yaml new file mode 100644 index 000000000..b7b3292b0 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: aws-cred + namespace: demo +data: + access_key: N2I2bl== + secret_key: N2I2bl== diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secretengine.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secretengine.yaml new file mode 100644 index 000000000..ab5dd722f --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secretengine.yaml @@ -0,0 +1,14 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: aws-secret-engine + namespace: demo +spec: + vaultRef: + name: vault + aws: + credentialSecret: aws-cred + region: us-east-1 + leaseConfig: + lease: 1h + leaseMax: 1h \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secretenginerole.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secretenginerole.yaml new file mode 100644 index 000000000..7556f1769 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secretenginerole.yaml @@ -0,0 +1,20 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: AWSRole +metadata: + name: aws-role + namespace: demo +spec: + secretEngineRef: + name: aws-secret-engine + credentialType: iam_user + policyDocument: | + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "ec2:*", + "Resource": "*" + } + ] + } diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secretrolebinding.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secretrolebinding.yaml new file mode 100644 index 000000000..68c03a003 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/secretrolebinding.yaml @@ -0,0 +1,13 @@ +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-r-binding + namespace: dev +spec: + roles: + - kind: AWSRole + name: aws-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/serviceaccount.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/serviceaccount.yaml new file mode 100644 index 000000000..66bac1f05 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: test \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/vaultserver.yaml new file mode 100644 index 000000000..1017c6396 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/secret-engines/secret-role-binding/vaultserver.yaml @@ -0,0 +1,38 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.7.3 + replicas: 3 + backend: + raft: + path: "/vault/data" + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: DoNotTerminate \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/vault-ops-request/issuer.yaml b/content/docs/v2025.11.21/examples/guides/vault-ops-request/issuer.yaml new file mode 100644 index 000000000..88017ab5e --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-ops-request/issuer.yaml @@ -0,0 +1,8 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: issuer + namespace: demo +spec: + ca: + secretName: vault-ca \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/vault-ops-request/new-issuer.yaml b/content/docs/v2025.11.21/examples/guides/vault-ops-request/new-issuer.yaml new file mode 100644 index 000000000..af1c94465 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-ops-request/new-issuer.yaml @@ -0,0 +1,8 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: new-issuer + namespace: demo +spec: + ca: + secretName: vault-new-ca \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-add-tls.yaml b/content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-add-tls.yaml new file mode 100644 index 000000000..9ded24c05 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-add-tls.yaml @@ -0,0 +1,21 @@ +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: vault-ops-add-tls + namespace: demo +spec: + type: ReconfigureTLS + vaultRef: + name: vault + tls: + issuerRef: + name: issuer + kind: Issuer + apiGroup: "cert-manager.io" + certificates: + - alias: client + subject: + organizations: + - appscode + organizationalUnits: + - client \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-change-issuer.yaml b/content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-change-issuer.yaml new file mode 100644 index 000000000..18e94fec9 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-change-issuer.yaml @@ -0,0 +1,14 @@ +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: vault-ops-change-issuer + namespace: demo +spec: + type: ReconfigureTLS + vaultRef: + name: vault + tls: + issuerRef: + name: new-issuer + kind: Issuer + apiGroup: "cert-manager.io" \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-remove.yaml b/content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-remove.yaml new file mode 100644 index 000000000..053cf91e8 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-remove.yaml @@ -0,0 +1,11 @@ +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: vault-ops-remove + namespace: demo +spec: + type: ReconfigureTLS + vaultRef: + name: vault + tls: + remove: true \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-rotate.yaml b/content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-rotate.yaml new file mode 100644 index 000000000..529e69c1a --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-ops-request/vault-ops-rotate.yaml @@ -0,0 +1,11 @@ +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: vault-ops-rotate + namespace: demo +spec: + type: ReconfigureTLS + vaultRef: + name: vault + tls: + rotateCertificates: true \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/vault-ops-request/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/vault-ops-request/vaultserver.yaml new file mode 100644 index 000000000..79d331f92 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-ops-request/vaultserver.yaml @@ -0,0 +1,32 @@ +apiVersion: kubevault.com/v1alpha2 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.10.3 + replicas: 3 + allowedSecretEngines: + namespaces: + from: All + secretEngines: + - gcp + backend: + raft: + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: WipeOut \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/vault-server/appBinding.yaml b/content/docs/v2025.11.21/examples/guides/vault-server/appBinding.yaml new file mode 100644 index 000000000..a2b1f3c00 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-server/appBinding.yaml @@ -0,0 +1,17 @@ +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault + namespace: demo +spec: + clientConfig: + url: https://e2a3839b.ngrok.io + insecureSkipTLSVerify: true + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: kubernetes ## Kubernetes auth is enabled in this path + vaultRole: vault-role ## auth-role name against which login will be done + kubernetes: + serviceAccountName: vault ## service account name + usePodServiceAccountForCSIDriver: true ## required while using CSI driver diff --git a/content/docs/v2025.11.21/examples/guides/vault-server/ca.crt b/content/docs/v2025.11.21/examples/guides/vault-server/ca.crt new file mode 100644 index 000000000..d67be76be --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-server/ca.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICyDCCAbCgAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl +cm5ldGVzMB4XDTE5MTExNDEyMDkxOFoXDTI5MTExMTEyMDkxOFowFTETMBEGA1UE +AxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMgc +UHarPqlczLlcUqNUHHM5yIyuE36S0EjSwqinHmRWcJIM5k+ktYkN6+9OQ+4SiQWf +cmUlnP7nx+vvL8H122zt6PJ+TZEfw1/qPZ5m3lsFeDtfSjf9tWv4Us/0cd8A2XrV +O6DlqyUARCN2dI8eUOGcVHblMeZeKQh7zxNVkHainijuPwTQwDnrTMz/zEap9m2G +upaAlk0fBQUkMB6D/seuL/XcrKKa7Rq5zDotZQBkowMaYfJzVK0Dz0dp4t42V7M2 +rkyRW0RNi96s1WMxxh+HNpK7RvPdXhTH6k5n8ls/qfi493sc1j4v6AQN3dnlRXJi +jw+vdurYtuATxFND528CAwEAAaMjMCEwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBABXnF+ugf2n4jGEF/H9U2Mnv7s29 +T6C7jrwGE8aIMSxKN5e4/+Xn7EY2c1yxv5Djju6doh8re+pf9ZBgYaUlD3TueuN2 +f5X1kcoQLWlFmMOb+7VNVmttUID9g9Ep6RJo3V2j2ru3jGe3sVLFQFKUFPyAyZV2 +wDAbNZW7PfsUxL3GfxUycOjzs83Y/+Mr9F4m+p9QCGV/fvjix1U9WV7z8dJo3W/i +p3J1VhQTVUoS/bMoXVKn6tFP5Ns/KSvKJNdvYN7uG1bAqmtLcaLWecImOb1fS/dP +y67FPCX16KVZtHcngvUDj+eYl81RVay7gVsbIkkOvxVkdWY8DWr32OF0P0A= +-----END CERTIFICATE----- diff --git a/content/docs/v2025.11.21/examples/guides/vault-server/clusterRoleBinding.yaml b/content/docs/v2025.11.21/examples/guides/vault-server/clusterRoleBinding.yaml new file mode 100644 index 000000000..d54d58ea9 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-server/clusterRoleBinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: role-tokenreview-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: token-reviewer + namespace: demo \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/vault-server/secret-policy.yaml b/content/docs/v2025.11.21/examples/guides/vault-server/secret-policy.yaml new file mode 100644 index 000000000..940152454 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-server/secret-policy.yaml @@ -0,0 +1,17 @@ +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: custom-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "sys/policy" { + capabilities = ["read", "list", "create", "update"] + } + + path "sys/policy/*" { + capabilities = ["read"] + } + diff --git a/content/docs/v2025.11.21/examples/guides/vault-server/vault.hcl b/content/docs/v2025.11.21/examples/guides/vault-server/vault.hcl new file mode 100644 index 000000000..1725073c2 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-server/vault.hcl @@ -0,0 +1,27 @@ +path "sys/mounts" { + capabilities = ["read", "list"] +} +path "sys/mounts/*" { + capabilities = ["create", "read", "update", "delete"] +} +path "sys/leases/revoke/*" { + capabilities = ["update"] +} +path "sys/policy/*" { + capabilities = ["create", "update", "read", "delete", "list"] +} +path "sys/policy" { + capabilities = ["read", "list"] +} +path "sys/policies" { + capabilities = ["read", "list"] +} +path "sys/policies/*" { + capabilities = ["create", "update", "read", "delete", "list"] +} +path "auth/kubernetes/role" { + capabilities = ["read", "list"] +} +path "auth/kubernetes/role/*" { + capabilities = ["create", "update", "read", "delete", "list"] +} \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/vault-server/vaultserver.yaml b/content/docs/v2025.11.21/examples/guides/vault-server/vaultserver.yaml new file mode 100644 index 000000000..c0218c98c --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-server/vaultserver.yaml @@ -0,0 +1,23 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + replicas: 1 + version: "1.2.3" + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + backend: + inmem: {} + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/guides/vault-server/vaultserverversion.yaml b/content/docs/v2025.11.21/examples/guides/vault-server/vaultserverversion.yaml new file mode 100644 index 000000000..6d4061a52 --- /dev/null +++ b/content/docs/v2025.11.21/examples/guides/vault-server/vaultserverversion.yaml @@ -0,0 +1,12 @@ +apiVersion: catalog.kubevault.com/v1alpha1 +kind: VaultServerVersion +metadata: + name: 1.2.2 +spec: + exporter: + image: kubevault/vault-exporter:v0.1.0 + unsealer: + image: kubevault/vault-unsealer:v0.3.0 + vault: + image: vault:1.2.2 + version: 1.2.2 diff --git a/content/docs/v2025.11.21/examples/monitoring/csi-driver/prom-builtin-conf.yaml b/content/docs/v2025.11.21/examples/monitoring/csi-driver/prom-builtin-conf.yaml new file mode 100644 index 000000000..f133b62d8 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/csi-driver/prom-builtin-conf.yaml @@ -0,0 +1,102 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-config + labels: + name: prometheus-config + namespace: monitoring +data: + prometheus.yml: |- + global: + scrape_interval: 5s + evaluation_interval: 5s + scrape_configs: + - job_name: 'csi-vault-controller' + honor_labels: true + kubernetes_sd_configs: + - role: endpoints + # Kubernetes apiserver serve metrics on a TLS secure endpoints. so, we have to use "https" scheme + scheme: https + # we have to provide certificate to establish tls secure connection + tls_config: + ca_file: /etc/prometheus/secret/csi-vault-apiserver-cert/tls.crt + server_name: csi-vault-controller.kube-system.svc + # bearer_token_file is required for authorizating prometheus server to Kubernetes apiserver + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + + relabel_configs: + - source_labels: [__meta_kubernetes_service_label_app] + separator: ; + regex: csi-vault + replacement: $1 + action: keep + - source_labels: [__meta_kubernetes_service_label_component] + separator: ; + regex: controller + replacement: $1 + action: keep + - source_labels: [__meta_kubernetes_endpoint_address_target_kind, __meta_kubernetes_endpoint_address_target_name] + separator: ; + regex: Node;(.*) + target_label: node + replacement: ${1} + action: replace + - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: kube-system;csi-vault-controller;api + - separator: ; + regex: (.*) + target_label: endpoint + replacement: api + action: replace + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*) + target_label: job + replacement: ${1} + action: replace + + - job_name: 'csi-vault-node' + honor_labels: true + kubernetes_sd_configs: + - role: endpoints + # Kubernetes apiserver serve metrics on a TLS secure endpoints. so, we have to use "https" scheme + scheme: https + # we have to provide certificate to establish tls secure connection + tls_config: + ca_file: /etc/prometheus/secret/csi-vault-apiserver-cert/tls.crt + server_name: csi-vault-node.kube-system.svc + # bearer_token_file is required for authorizating prometheus server to Kubernetes apiserver + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + + relabel_configs: + - source_labels: [__meta_kubernetes_service_label_app] + separator: ; + regex: csi-vault + replacement: $1 + action: keep + - source_labels: [__meta_kubernetes_service_label_component] + separator: ; + regex: node + replacement: $1 + action: keep + - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: kube-system;csi-vault-node;api + - source_labels: [__meta_kubernetes_endpoint_address_target_kind, __meta_kubernetes_endpoint_address_target_name] + separator: ; + regex: Node;(.*) + target_label: node + replacement: ${1} + action: replace + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*) + target_label: job + replacement: ${1} + action: replace + - separator: ; + regex: (.*) + target_label: endpoint + replacement: api + action: replace \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/monitoring/csi-driver/prom-builtin-deployment.yaml b/content/docs/v2025.11.21/examples/monitoring/csi-driver/prom-builtin-deployment.yaml new file mode 100644 index 000000000..74b246643 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/csi-driver/prom-builtin-deployment.yaml @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: prometheus-demo + name: prometheus + namespace: monitoring +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + spec: + containers: + - args: + - --config.file=/etc/prometheus/prometheus.yml + - --storage.tsdb.path=/prometheus/ + image: prom/prometheus:v2.5.0 + imagePullPolicy: IfNotPresent + name: prometheus + ports: + - containerPort: 9090 + protocol: TCP + volumeMounts: + - mountPath: /etc/prometheus/ + name: prometheus-config + - mountPath: /prometheus/ + name: prometheus-storage + - mountPath: /etc/prometheus/secret/csi-vault-apiserver-cert + name: csi-vault-apiserver-cert + serviceAccountName: prometheus + volumes: + - configMap: + defaultMode: 420 + name: prometheus-config + name: prometheus-config + - emptyDir: {} + name: prometheus-storage + - name: csi-vault-apiserver-cert + secret: + defaultMode: 420 + secretName: csi-vault-apiserver-cert + items: + - path: tls.crt + key: tls.crt \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/monitoring/csi-driver/prom-coreos-crd.yaml b/content/docs/v2025.11.21/examples/monitoring/csi-driver/prom-coreos-crd.yaml new file mode 100644 index 000000000..d963a6256 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/csi-driver/prom-coreos-crd.yaml @@ -0,0 +1,18 @@ +apiVersion: monitoring.coreos.com/v1 +kind: Prometheus +metadata: + name: prometheus + namespace: monitoring + labels: + k8s-app: prometheus +spec: + replicas: 1 + serviceAccountName: prometheus + serviceMonitorSelector: + matchLabels: + k8s-app: prometheus + secrets: + - csi-vault-apiserver-cert + resources: + requests: + memory: 400Mi \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/monitoring/grafana/dashboard.json b/content/docs/v2025.11.21/examples/monitoring/grafana/dashboard.json new file mode 100644 index 000000000..35c361b24 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/grafana/dashboard.json @@ -0,0 +1,3390 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.1.0" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1525183847469, + "links": [], + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorPostfix": false, + "colorValue": true, + "colors": [ + "#962d82", + "rgb(113, 165, 208)", + "#d44a3a" + ], + "datasource": null, + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 83, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(vault_info) by (vault_cluster, kubernetes_namespace)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Vault Cluser : {{ kubernetes_namespace }}/{{vault_cluster}}", + "refId": "A" + } + ], + "thresholds": "", + "title": "Vault Cluster", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "2" + } + ], + "valueName": "name" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": null, + "decimals": 0, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 3 + }, + "id": 69, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": null, + "sortDesc": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "{vault_cluster=\"example\"}", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(vault_up) by ( vault_cluster, pod_name, kubernetes_namespace)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ pod_name }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Up Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": 1 + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": null, + "decimals": 0, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 3 + }, + "id": 74, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "{vault_cluster=\"example\"}", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(1 - vault_up) by ( vault_cluster, pod_name, kubernetes_namespaces)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ pod_name }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Down Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": 1 + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": null, + "decimals": 0, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 3 + }, + "id": 71, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(vault_initialized) by ( vault_cluster, pod_name, kubernetes_namespace)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ pod_name }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Initialized Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "decimals": 0, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 10 + }, + "id": 75, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(1 - vault_sealed) by (vault_cluster, pod_name, kubernetes_namespace)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ pod_name }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Unsealed Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 10 + }, + "id": 73, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(vault_sealed) by (vault_cluster, pod_name)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{pod_name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Sealed Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 10 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/.*sys_bytes.*/", + "dashes": true, + "fill": 0 + }, + { + "alias": "/.*total_bytes.*/", + "fill": 0 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max(vault_runtime_alloc_bytes) by (vault_cluster)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "allocated_bytes : {{ vault_cluster }}", + "refId": "A" + }, + { + "expr": "max(vault_runtime_sys_bytes) by (vault_cluster)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "system_bytes : {{ vault_cluster }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Runtime Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 17 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg(vault_runtime_total_gc_pause_ns / 1000000 ) by (vault_cluster)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{vault_cluster}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "GC Pause Time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 17 + }, + "id": 79, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(vault_route_count[1m])) by (vault_cluster)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{vault_cluster}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "QPS", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 17 + }, + "id": 77, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max(vault_route{quantile=\"0.99\"}) by (vault_cluster)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "99th Percentile : {{vault_cluster}}", + "refId": "A" + }, + { + "expr": "max(vault_route{quantile=\"0.5\"}) by (vault_cluster)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "50th Percentile : {{vault_cluster}}", + "refId": "B" + }, + { + "expr": "sum(rate(vault_route_sum[5m])) by (vault_cluster) / sum(rate(vault_route_count[5m])) by (vault_cluster)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Average : {{vault_cluster}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Latency", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "prom", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 23 + }, + "id": 65, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(vault_runtime_num_goroutines)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "vault_cluster : {{vault_cluster}}", + "refId": "A" + } + ], + "thresholds": "1000, 10000", + "title": "Goroutines", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "gridPos": { + "h": 6, + "w": 10, + "x": 4, + "y": 23 + }, + "id": 62, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(idelta(vault_route_count{method=~\"create|delete|renew\"}[5m])) by (method, path)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ method }} : {{path}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Modify by Path", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "gridPos": { + "h": 6, + "w": 10, + "x": 14, + "y": 23 + }, + "id": 64, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(idelta(vault_route_count{method=~\"read\"}[5m])) by (method, path)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ method }} : {{path}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Read by Path", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 16, + "panels": [], + "title": "Token", + "type": "row" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "prom", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 30 + }, + "id": 8, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "vault_token_create_count - vault_token_store_count", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "1,3", + "title": "Pending Tokens", + "type": "singlestat", + "valueFontSize": "150%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "aliasColors": { + "Lookup": "#0a50a1" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 6, + "w": 10, + "x": 4, + "y": 30 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(vault_token_lookup_count[1m])) by (vault_cluster)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Lookup : {{vault_cluster}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Token Lookup", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Create": "rgb(84, 183, 90)", + "Store": "#0a437c" + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 6, + "w": 10, + "x": 14, + "y": 30 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(vault_token_create_count) by (vault_cluster)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "Create : {{vault_cluster}}", + "refId": "A" + }, + { + "expr": "sum(vault_token_store_count) by (vault_cluster)", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Store : {{vault_cluster}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Token", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 20, + "panels": [], + "title": "Audit", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 6, + "w": 14, + "x": 0, + "y": 37 + }, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(vault_audit_log_request_count[1m])) by (vault_cluster)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "Request : {{vault_cluster}}", + "refId": "A" + }, + { + "expr": "sum(irate(vault_audit_log_response_count[1m])) by (vault_cluster)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "Response : {{vault_cluster}}", + "refId": "B" + }, + { + "expr": "sum(irate(vault_core_handle_request_count[1m])) by (vault_cluster)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Handled : {{vault_cluster}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Audit Log Request", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 6, + "w": 10, + "x": 14, + "y": 37 + }, + "id": 36, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": false, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(idelta(vault_route_count{method=~\"rollback\"}[5m])) by (method, path)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ method }}:{{path}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Auth Rollback", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 43 + }, + "id": 18, + "panels": [], + "title": "Policy", + "type": "row" + }, + { + "aliasColors": { + "set": "#629e51" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 44 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(vault_policy_set_policy_count[1m])) by (vault_cluster)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "set : {{ vault_cluster }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Policy Set", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "transparent": false, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "GET": "#1f78c1" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 44 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(vault_policy_get_policy_count[1m])) by (vault_cluster)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "get : {{ vault_cluster }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Policy Get", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 50 + }, + "id": 40, + "panels": [], + "title": "Database Secret Engine", + "type": "row" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "#7eb26d", + "#d44a3a" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 51 + }, + "id": 42, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "vault_database_initialize_total - vault_database_close_total", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "Num of Databases", + "type": "singlestat", + "valueFontSize": "150%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "aliasColors": { + "create_error": "#629e51" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 4, + "y": 51 + }, + "id": 46, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(vault_database_initialize_error_total[5m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "create_error", + "refId": "A" + }, + { + "expr": "rate(vault_database_close_error_total[5m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "renew_error", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Database Initialize and Close Error", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "#7eb26d", + "#d44a3a" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 12, + "y": 51 + }, + "id": 45, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "vault_database_user_create_total - vault_database_user_revoke_total", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Active User", + "type": "singlestat", + "valueFontSize": "150%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "aliasColors": { + "create_error": "#629e51" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 51 + }, + "id": 44, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(vault_database_user_create_error_total[5m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "create_error", + "refId": "A" + }, + { + "expr": "rate(vault_database_user_renew_error_total[5m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "renew_error", + "refId": "B" + }, + { + "expr": "rate(vault_database_user_revoke_error_total[5m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "revoke_error", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "User Create, Renew and Revoke Error", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 57 + }, + "id": 32, + "panels": [], + "title": "Google Cloud Storage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 58 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(irate(vault_gcs_list_count[10m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "list", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Cloud Storage List", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "GET": "#1f78c1" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 58 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(vault_gcs_get_count[10m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "GET", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Cloud Storage GET", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Delete": "#e24d42" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 58 + }, + "id": 29, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(vault_gcs_delete_count[10m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Delete", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Cloud Storage Delete", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 58 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(vault_gcs_put_sum[5m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "PUT", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Cloud Storage PUT", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 63 + }, + "id": 54, + "panels": [], + "title": "Amazon S3", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 64 + }, + "id": 47, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(irate(vault_s3_list_count[10m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "list", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "S3 Storage List", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "GET": "#1f78c1" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 64 + }, + "id": 48, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(vault_s3_get_count[10m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "GET", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "S3 Storage GET", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Delete": "#e24d42" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 64 + }, + "id": 49, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(vault_s3_delete_count[10m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Delete", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "S3 Storage Delete", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 64 + }, + "id": 50, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(vault_s3_put_sum[5m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "PUT", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "S3 Storage PUT", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 69 + }, + "id": 56, + "panels": [], + "title": "Microsoft Azure Storage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 70 + }, + "id": 57, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(irate(vault_azure_list_count[10m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "list", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Azure Storage List", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "GET": "#1f78c1" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 70 + }, + "id": 58, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(vault_azure_get_count[10m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "GET", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Azure Storage GET", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Delete": "#e24d42" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 70 + }, + "id": 59, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(vault_azure_delete_count[10m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Delete", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Azure Storage Delete", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prom", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 70 + }, + "id": 60, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(vault_azure_put_sum[5m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "PUT", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Azure Storage PUT", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": false, + "schemaVersion": 16, + "style": "dark", + "tags": [], + "time": { + "from": "now-12h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Vault Cluster Health", + "uid": "1HJSjizmkdd", + "version": 24 +} diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-operator/prom-builtin-deployment.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prom-builtin-deployment.yaml new file mode 100644 index 000000000..24508c5de --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prom-builtin-deployment.yaml @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: prometheus-demo + name: prometheus + namespace: monitoring +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + spec: + containers: + - args: + - --config.file=/etc/prometheus/prometheus.yml + - --storage.tsdb.path=/prometheus/ + image: prom/prometheus:v2.5.0 + imagePullPolicy: IfNotPresent + name: prometheus + ports: + - containerPort: 9090 + protocol: TCP + volumeMounts: + - mountPath: /etc/prometheus/ + name: prometheus-config + - mountPath: /prometheus/ + name: prometheus-storage + - mountPath: /etc/prometheus/secret/vault-operator-apiserver-cert + name: vault-operator-apiserver-cert + serviceAccountName: prometheus + volumes: + - configMap: + defaultMode: 420 + name: prometheus-config + name: prometheus-config + - emptyDir: {} + name: prometheus-storage + - name: vault-operator-apiserver-cert + secret: + defaultMode: 420 + secretName: vault-operator-apiserver-cert + items: + - path: tls.crt + key: tls.crt \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-operator/prom-coreos-crd.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prom-coreos-crd.yaml new file mode 100644 index 000000000..db296bc89 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prom-coreos-crd.yaml @@ -0,0 +1,18 @@ +apiVersion: monitoring.coreos.com/v1 +kind: Prometheus +metadata: + name: prometheus + namespace: monitoring + labels: + k8s-app: prometheus +spec: + replicas: 1 + serviceAccountName: prometheus + serviceMonitorSelector: + matchLabels: + k8s-app: prometheus + secrets: + - vault-operator-apiserver-cert + resources: + requests: + memory: 400Mi \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-operator/prom-server-conf.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prom-server-conf.yaml new file mode 100644 index 000000000..4e270fe16 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prom-server-conf.yaml @@ -0,0 +1,52 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-config + labels: + name: prometheus-config + namespace: monitoring +data: + prometheus.yml: |- + global: + scrape_interval: 5s + evaluation_interval: 5s + scrape_configs: + - job_name: 'vault-apiservers' + honor_labels: true + kubernetes_sd_configs: + - role: endpoints + # Kubernetes apiserver serve metrics on a TLS secure endpoints. so, we have to use "https" scheme + scheme: https + # we have to provide certificate to establish tls secure connection + tls_config: + ca_file: /etc/prometheus/secret/vault-operator-apiserver-cert/tls.crt + server_name: vault-operator.kube-system.svc + # bearer_token_file is required for authorizating prometheus server to Kubernetes apiserver + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + + relabel_configs: + - source_labels: [__meta_kubernetes_service_label_app] + separator: ; + regex: vault-operator + replacement: $1 + action: keep + - source_labels: [__meta_kubernetes_endpoint_address_target_kind, __meta_kubernetes_endpoint_address_target_name] + separator: ; + regex: Node;(.*) + target_label: node + replacement: ${1} + action: replace + - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: kube-system;vault-operator;api + - separator: ; + regex: (.*) + target_label: endpoint + replacement: api + action: replace + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*) + target_label: job + replacement: ${1} + action: replace \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-builtin.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-builtin.yaml new file mode 100644 index 000000000..fbe9920cb --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-builtin.yaml @@ -0,0 +1,100 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-server +rules: +- apiGroups: [""] + resources: + - nodes + - nodes/proxy + - services + - endpoints + - pods + verbs: ["get", "list", "watch"] +- apiGroups: + - extensions + resources: + - ingresses + verbs: ["get", "list", "watch"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus-server + namespace: demo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-server +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-server +subjects: +- kind: ServiceAccount + name: prometheus-server + namespace: demo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: prometheus-demo + name: prometheus + namespace: monitoring +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + spec: + containers: + - args: + - --config.file=/etc/prometheus/prometheus.yml + - --storage.tsdb.path=/prometheus/ + image: prom/prometheus:v2.5.0 + imagePullPolicy: IfNotPresent + name: prometheus + ports: + - containerPort: 9090 + protocol: TCP + volumeMounts: + - mountPath: /etc/prometheus/ + name: prometheus-config + - mountPath: /prometheus/ + name: prometheus-storage + - mountPath: /etc/prometheus/secret/vault-operator-apiserver-cert + name: vault-operator-apiserver-cert + serviceAccountName: prometheus + volumes: + - configMap: + defaultMode: 420 + name: prometheus-config + name: prometheus-config + - emptyDir: {} + name: prometheus-storage + - name: vault-operator-apiserver-cert + secret: + defaultMode: 420 + secretName: vault-operator-apiserver-cert +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus-service + namespace: demo +spec: + selector: + app: prometheus-server + type: NodePort + ports: + - port: 9090 + targetPort: 9090 + nodePort: 30901 diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-coreos-operator.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-coreos-operator.yaml new file mode 100644 index 000000000..036e76a6d --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-coreos-operator.yaml @@ -0,0 +1,108 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: demo +spec: + finalizers: + - kubernetes +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-operator +rules: +- apiGroups: + - extensions + resources: + - thirdpartyresources + verbs: + - "*" +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - "*" +- apiGroups: + - monitoring.coreos.com + resources: + - alertmanagers + - prometheuses + - servicemonitors + verbs: + - "*" +- apiGroups: + - apps + resources: + - statefulsets + verbs: ["*"] +- apiGroups: [""] + resources: + - configmaps + - secrets + verbs: ["*"] +- apiGroups: [""] + resources: + - pods + verbs: ["list", "delete"] +- apiGroups: [""] + resources: + - services + - endpoints + verbs: ["get", "create", "update"] +- apiGroups: [""] + resources: + - nodes + verbs: ["list", "watch"] +- apiGroups: [""] + resources: + - namespaces + verbs: ["list"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus-operator + namespace: demo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-operator +subjects: +- kind: ServiceAccount + name: prometheus-operator + namespace: demo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus-operator + namespace: demo + labels: + operator: prometheus +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + operator: prometheus + spec: + serviceAccountName: prometheus-operator + containers: + - name: prometheus-operator + image: quay.io/coreos/prometheus-operator:v0.16.0 + resources: + requests: + cpu: 100m + memory: 50Mi + limits: + cpu: 200m + memory: 100Mi diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-coreos.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-coreos.yaml new file mode 100644 index 000000000..c722424c4 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-coreos.yaml @@ -0,0 +1,68 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus + namespace: demo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus +subjects: +- kind: ServiceAccount + name: prometheus + namespace: demo +--- +apiVersion: monitoring.coreos.com/v1 +kind: Prometheus +metadata: + name: prometheus + namespace: demo +spec: + serviceAccountName: prometheus + serviceMonitorSelector: + matchLabels: + app: vault + version: v1.7.0 + resources: + requests: + memory: 400Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: demo +spec: + type: LoadBalancer + ports: + - name: web + nodePort: 30900 + port: 9090 + protocol: TCP + targetPort: web + selector: + prometheus: prometheus \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-service.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-service.yaml new file mode 100644 index 000000000..bf9b1c75f --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-operator/prometheus-service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: monitoring +spec: + type: ClusterIP + ports: + - name: web + port: 9090 + protocol: TCP + targetPort: 9090 + selector: + app: prometheus diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-operator/vault-server-builtin.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-operator/vault-server-builtin.yaml new file mode 100644 index 000000000..ba4610306 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-operator/vault-server-builtin.yaml @@ -0,0 +1,32 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + replicas: 1 + version: 1.2.0 + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + backend: + inmem: {} + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: "WipeOut" diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-operator/vault-server-coreos.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-operator/vault-server-coreos.yaml new file mode 100644 index 000000000..067ee6a82 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-operator/vault-server-coreos.yaml @@ -0,0 +1,32 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + replicas: 1 + version: 1.2.0 + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + backend: + inmem: {} + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: "WipeOut" diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-server/prom-server-conf.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-server/prom-server-conf.yaml new file mode 100644 index 000000000..3b108ad84 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-server/prom-server-conf.yaml @@ -0,0 +1,46 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-config + labels: + name: prometheus-config + namespace: monitoring +data: + prometheus.yml: |- + global: + scrape_interval: 5s + evaluation_interval: 5s + scrape_configs: + - job_name: 'kubernetes-service-endpoints' + + kubernetes_sd_configs: + - role: endpoints + + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-builtin.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-builtin.yaml new file mode 100644 index 000000000..41d558137 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-builtin.yaml @@ -0,0 +1,90 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-server +rules: +- apiGroups: [""] + resources: + - nodes + - nodes/proxy + - services + - endpoints + - pods + verbs: ["get", "list", "watch"] +- apiGroups: + - extensions + resources: + - ingresses + verbs: ["get", "list", "watch"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus-server + namespace: demo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-server +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-server +subjects: +- kind: ServiceAccount + name: prometheus-server + namespace: demo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus-server + namespace: demo +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus-server + template: + metadata: + labels: + app: prometheus-server + spec: + serviceAccountName: prometheus-server + containers: + - name: prometheus + image: prom/prometheus:v2.1.0 + args: + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.path=/prometheus/" + ports: + - containerPort: 9090 + volumeMounts: + - name: prometheus-config-volume + mountPath: /etc/prometheus/ + - name: prometheus-storage-volume + mountPath: /prometheus/ + volumes: + - name: prometheus-config-volume + configMap: + defaultMode: 420 + name: prometheus-server-conf + - name: prometheus-storage-volume + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus-service + namespace: demo +spec: + selector: + app: prometheus-server + type: NodePort + ports: + - port: 9090 + targetPort: 9090 + nodePort: 30901 diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-coreos-operator.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-coreos-operator.yaml new file mode 100644 index 000000000..036e76a6d --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-coreos-operator.yaml @@ -0,0 +1,108 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: demo +spec: + finalizers: + - kubernetes +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-operator +rules: +- apiGroups: + - extensions + resources: + - thirdpartyresources + verbs: + - "*" +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - "*" +- apiGroups: + - monitoring.coreos.com + resources: + - alertmanagers + - prometheuses + - servicemonitors + verbs: + - "*" +- apiGroups: + - apps + resources: + - statefulsets + verbs: ["*"] +- apiGroups: [""] + resources: + - configmaps + - secrets + verbs: ["*"] +- apiGroups: [""] + resources: + - pods + verbs: ["list", "delete"] +- apiGroups: [""] + resources: + - services + - endpoints + verbs: ["get", "create", "update"] +- apiGroups: [""] + resources: + - nodes + verbs: ["list", "watch"] +- apiGroups: [""] + resources: + - namespaces + verbs: ["list"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus-operator + namespace: demo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-operator +subjects: +- kind: ServiceAccount + name: prometheus-operator + namespace: demo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus-operator + namespace: demo + labels: + operator: prometheus +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + operator: prometheus + spec: + serviceAccountName: prometheus-operator + containers: + - name: prometheus-operator + image: quay.io/coreos/prometheus-operator:v0.16.0 + resources: + requests: + cpu: 100m + memory: 50Mi + limits: + cpu: 200m + memory: 100Mi diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-coreos.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-coreos.yaml new file mode 100644 index 000000000..c722424c4 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-coreos.yaml @@ -0,0 +1,68 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus + namespace: demo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus +subjects: +- kind: ServiceAccount + name: prometheus + namespace: demo +--- +apiVersion: monitoring.coreos.com/v1 +kind: Prometheus +metadata: + name: prometheus + namespace: demo +spec: + serviceAccountName: prometheus + serviceMonitorSelector: + matchLabels: + app: vault + version: v1.7.0 + resources: + requests: + memory: 400Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: demo +spec: + type: LoadBalancer + ports: + - name: web + nodePort: 30900 + port: 9090 + protocol: TCP + targetPort: web + selector: + prometheus: prometheus \ No newline at end of file diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-service.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-service.yaml new file mode 100644 index 000000000..bf9b1c75f --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-server/prometheus-service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: monitoring +spec: + type: ClusterIP + ports: + - name: web + port: 9090 + protocol: TCP + targetPort: 9090 + selector: + app: prometheus diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-server/vault-server-builtin.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-server/vault-server-builtin.yaml new file mode 100644 index 000000000..067ee6a82 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-server/vault-server-builtin.yaml @@ -0,0 +1,32 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + replicas: 1 + version: 1.2.0 + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + backend: + inmem: {} + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: "WipeOut" diff --git a/content/docs/v2025.11.21/examples/monitoring/vault-server/vault-server-coreos.yaml b/content/docs/v2025.11.21/examples/monitoring/vault-server/vault-server-coreos.yaml new file mode 100644 index 000000000..067ee6a82 --- /dev/null +++ b/content/docs/v2025.11.21/examples/monitoring/vault-server/vault-server-coreos.yaml @@ -0,0 +1,32 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + replicas: 1 + version: 1.2.0 + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + backend: + inmem: {} + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: "WipeOut" diff --git a/content/docs/v2025.11.21/examples/vaultserver_inmem_k8s_unsealer.yaml b/content/docs/v2025.11.21/examples/vaultserver_inmem_k8s_unsealer.yaml new file mode 100644 index 000000000..c88fca894 --- /dev/null +++ b/content/docs/v2025.11.21/examples/vaultserver_inmem_k8s_unsealer.yaml @@ -0,0 +1,16 @@ +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: example + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + inmem: {} + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys diff --git a/content/docs/v2025.11.21/guides/README.md b/content/docs/v2025.11.21/guides/README.md new file mode 100644 index 000000000..baa647188 --- /dev/null +++ b/content/docs/v2025.11.21/guides/README.md @@ -0,0 +1,59 @@ +--- +title: Table of Contents | Guides +description: Table of Contents | Guides +menu: + docs_v2025.11.21: + identifier: guides-readme + name: Readme + parent: guides + weight: -1 +menu_name: docs_v2025.11.21 +section_menu_id: guides +url: /docs/v2025.11.21/guides/ +aliases: +- /docs/v2025.11.21/guides/README/ +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Guides + +Guides show you how to perform tasks with KubeVault operator and Vault CSI driver. + +## Using KubeVault operator + +- To deploy Vault in AWS EKS see [here](/docs/v2025.11.21/guides/platforms/eks). +- To deploy Vault in Google GKE see [here](/docs/v2025.11.21/guides/platforms/gke). +- To deploy Vault in Azure AKS see [here](/docs/v2025.11.21/guides/platforms/aks). +- To manage Vault policy see [here](/docs/v2025.11.21/guides/policy-management/overview). +- To manage Vault AWS secret engine see [here](/docs/v2025.11.21/guides/secret-engines/aws/overview). +- To manage Vault GCP secret engine see [here](/docs/v2025.11.21/guides/secret-engines/gcp/overview). +- To manage Vault Azure secret engine see [here](/docs/v2025.11.21/guides/secret-engines/azure/overview). +- To manage Vault MongoDB Database secret engine] see [here](/docs/v2025.11.21/guides/secret-engines/mongodb/overview). +- To manage Vault MySQL Database secret engine see [here](/docs/v2025.11.21/guides/secret-engines/mysql/overview). +- To manage Vault PostgreSQL Database secret engine see [here](/docs/v2025.11.21/guides/secret-engines/postgres/overview). +- To manage Vault Elasticsearch Database secret engine see [here](/docs/v2025.11.21/guides/secret-engines/elasticsearch/overview). +- To manage Vault MariaDB Database secret engine see [here](/docs/v2025.11.21/guides/secret-engines/mariadb/overview). +- To manage Vault Redis Database secret engine see [here](/docs/v2025.11.21/guides/secret-engines/redis/overview). +- To set up monitoring see [here](/docs/v2025.11.21/guides/monitoring/overview). +- To use KubeVault operator for external Vault see [here](/docs/v2025.11.21/guides/platforms/external-vault). +- To use KubeVault operator in multiple cluster for same Vault see [here](/docs/v2025.11.21/guides/platforms/multi-cluster-vault). + +## Using Vault CSI driver + +- To mount Azure secret engine secret in pod see [here](/docs/v2025.11.21/guides/secret-engines/azure/csi-driver). +- To mount AWS secret engine secret in pod see [here](/docs/v2025.11.21/guides/secret-engines/aws/csi-driver). +- To mount GCP secret engine secret in pod see [here](/docs/v2025.11.21/guides/secret-engines/gcp/csi-driver). +- To mount KV secret engine secret in pod see [here](/docs/v2025.11.21/guides/secret-engines/kv/csi-driver). +- To mount MongoDB Database secret engine secret in pod see [here](/docs/v2025.11.21/guides/secret-engines/mongodb/csi-driver). +- To mount MySQL Database secret engine secret in pod see [here](/docs/v2025.11.21/guides/secret-engines/mysql/csi-driver). +- To mount PostgreSQL Database secret engine secret in pod see [here](/docs/v2025.11.21/guides/secret-engines/postgres/csi-driver). +- To mount Elasticsearch Database secret engine secret in pod see [here](/docs/v2025.11.21/guides/secret-engines/elasticsearch/csi-driver). +- To mount MariaDB Database secret engine secret in pod see [here](/docs/v2025.11.21/guides/secret-engines/mariadb/csi-driver). +- To mount Redis Database secret engine secret in pod see [here](/docs/v2025.11.21/guides/secret-engines/redis/csi-driver). +- To mount PKI secret engine secret in pod see [here](/docs/v2025.11.21/guides/secret-engines/pki/csi-driver). +- To set up monitoring see [here](/docs/v2025.11.21/guides/monitoring/overview). diff --git a/content/docs/v2025.11.21/guides/_index.md b/content/docs/v2025.11.21/guides/_index.md new file mode 100755 index 000000000..c5a334523 --- /dev/null +++ b/content/docs/v2025.11.21/guides/_index.md @@ -0,0 +1,16 @@ +--- +title: Guides | KubeVault +menu: + docs_v2025.11.21: + identifier: guides + name: Guides + weight: 40 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/backup-restore/_index.md b/content/docs/v2025.11.21/guides/backup-restore/_index.md new file mode 100644 index 000000000..b2adfee12 --- /dev/null +++ b/content/docs/v2025.11.21/guides/backup-restore/_index.md @@ -0,0 +1,17 @@ +--- +title: Vault Backup Restore Guides | KubeVault +menu: + docs_v2025.11.21: + identifier: backup-restore-guides + name: Backup & Restore (Stash) + parent: guides + weight: 10 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/backup-restore/backup.md b/content/docs/v2025.11.21/guides/backup-restore/backup.md new file mode 100644 index 000000000..967c40c8c --- /dev/null +++ b/content/docs/v2025.11.21/guides/backup-restore/backup.md @@ -0,0 +1,371 @@ +--- +title: Vault Backup Restore Overview +menu: + docs_v2025.11.21: + identifier: backup-backup-restore-guides + name: Backup + parent: backup-restore-guides + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Backup Vault Cluster using Stash + +This guide will show you how you can take backup of your Vault cluster with Stash. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the `kubectl` command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using Minikube. +- Install KubeVault in your cluster following the steps [here](/docs/v2025.11.21/setup/README). +- Install Stash in your cluster following the steps [here](https://stash.run/docs/latest/setup). +- Install Stash `kubectl` plugin following the steps [here](https://stash.run/docs/latest/setup/install/kubectl-plugin/). +- If you are not familiar with how Stash backup and restore Vault cluster, please check the following concept section [here](/docs/v2025.11.21/concepts/backup-restore/overview). + +You have to be familiar with following custom resources: + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/appbinding) +- [Function](https://stash.run/docs/latest/concepts/crds/function/) +- [Task](https://stash.run/docs/latest/concepts/crds/task/) +- [BackupConfiguration](https://stash.run/docs/latest/concepts/crds/backupconfiguration/) +- [RestoreSession](https://stash.run/docs/latest/concepts/crds/restoresession/) + + +## Deploy Vault using KubeVault + +To keep everything isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +````bash +# create demo namespace +$ kubectl create ns demo +namespace/demo created +```` + +We're going to use Kubernetes secret to store the unseal-keys & root-token. A sample `VaultServer` manifest file may look like this: + +```yaml +apiVersion: kubevault.com/v1alpha2 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.10.3 + replicas: 3 + allowedSecretEngines: + namespaces: + from: All + backend: + raft: + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: WipeOut +``` + +Now, let's deploy the `VaultServer`: + +```bash +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/backup-restore/vaultserver.yaml +vaultserver.kubevault.com/vault created +``` + +`KubeVault` operator will create a `AppBinding` CRD on `VaultServer` deployment, which contains the necessary information +to take backup of the Vault instances. It'll have the same name & be created on the same namespace as the `Vault`. +Read more about `AppBinding` [here](/docs/v2025.11.21/concepts/vault-server-crds/appbinding). + +```bash +$ kubectl get appbinding -n demo vault -oyaml +``` + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault + namespace: demo +spec: + appRef: + apiGroup: kubevault.com + kind: VaultServer + name: vault + namespace: demo + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + backend: raft + backupTokenSecretRef: + name: vault-backup-token + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + stash: + addon: + backupTask: + name: vault-backup-1.10.3 + params: + - name: keyPrefix + value: k8s.kubevault.com.demo.vault + restoreTask: + name: vault-restore-1.10.3 + params: + - name: keyPrefix + value: k8s.kubevault.com.demo.vault + unsealer: + mode: + kubernetesSecret: + secretName: vault-keys + secretShares: 5 + secretThreshold: 3 + vaultRole: vault-policy-controller +``` + +Now, let's wait until all the vault pods come up & `VaultServer` phase becomes `Ready`. + +```bash +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +vault-0 2/2 Running 0 2m8s +vault-1 2/2 Running 0 91s +vault-2 2/2 Running 0 65s +``` + +```bash +$ kubectl get vaultserver -n demo +NAME REPLICAS VERSION STATUS AGE +vault 3 1.10.3 Ready 2m50s +``` + +At this stage, we've successfully deployed `Vault` using `KubeVault` operator & ready for taking `Backup`. + +Before, taking the backup, let's write some data in a `KV` secret engine. Let's export the necessary environment variables & port-forward from `vault` service +or exec into the vault pod in order to interact with it. + +```bash +$ export VAULT_TOKEN=(kubectl vault root-token get vaultserver vault -n demo --value-only) +$ export VAULT_ADDR='http://127.0.0.1:8200' +$ kubectl port-forward -n demo svc/vault 8200 +``` + +We can see the currently enabled list of secret engines. + +```bash +$ vault secrets list +Path Type Accessor Description +---- ---- -------- ----------- +cubbyhole/ cubbyhole cubbyhole_bb7c56f9 per-token private secret storage +identity/ identity identity_fa8431fa identity store +k8s.kubevault.com.kv.demo.vault-health/ kv kv_5129d194 n/a +sys/ system system_c7e0879a system endpoints used for control, policy and debugging +``` + +Let's enable a `KV` type secret engine: + +```bash +$ vault secrets enable kv +Success! Enabled the kv secrets engine at: kv/ +``` + +Write some dummy data in the secret engine path: + +```bash +$ vault kv put kv/name name=appscode +Success! Data written to: kv/name +``` + +Verify data written in `KV` secret engine: + +```bash +$ vault kv get kv/name +==== Data ==== +Key Value +--- ----- +name appscode +``` + +### Prepare Backend + +We are going to store our backed up data into a GCS bucket. We have to create a Secret with necessary credentials and a Repository crd to use this backend. If you want to use a different backend, +please read the respective backend configuration doc from [here](https://stash.run/docs/v2022.12.11/guides/backends/overview/). + +#### Create Secret + +Let’s create a secret called `gcs-secret` with access credentials to our desired GCS bucket, + +```bash +$ echo -n 'restic-pass' > RESTIC_PASSWORD +$ echo -n 'project-id' > GOOGLE_PROJECT_ID +$ cat sa.json > GOOGLE_SERVICE_ACCOUNT_JSON_KEY + +$ kubectl create secret generic -n demo gcs-secret \ + --from-file=./RESTIC_PASSWORD \ + --from-file=./GOOGLE_PROJECT_ID \ + --from-file=./GOOGLE_SERVICE_ACCOUNT_JSON_KEY +``` + +Now, we are ready to backup our workload’s data to our desired backend. + +#### Create Repository + +Now, create a `Repository` using this secret. Below is the YAML of Repository crd we are going to create, + +```yaml +apiVersion: stash.appscode.com/v1alpha1 +kind: Repository +metadata: + name: gcp-demo-repo + namespace: demo +spec: + backend: + gcs: + bucket: stash-testing + prefix: demo-vault + storageSecretName: repository-creds + usagePolicy: + allowedNamespaces: + from: Same + wipeOut: false +``` + +```bash +$ kbuectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/backup-restore/repository.yaml +``` + +Now, we are ready to backup our sample data into this backend. + +### Backup + +We have to create a BackupConfiguration crd targeting the stash-demo StatefulSet that we have deployed earlier. +Stash will inject a sidecar container into the target. It will also create a CronJob to take periodic +backup of /source/data directory of the target. + +#### Create BackupConfiguration + +Below is the YAML of the BackupConfiguration crd that we are going to create, + +```yaml +apiVersion: stash.appscode.com/v1beta1 +kind: BackupConfiguration +metadata: + name: demo-backup + namespace: demo +spec: + driver: Restic + repository: + name: gcp-demo-repo + namespace: demo + schedule: "*/5 * * * *" + timeOut: 2h + target: + ref: + apiVersion: appcatalog.appscode.com/v1alpha1 + kind: AppBinding + name: vault + runtimeSettings: + container: + securityContext: + runAsUser: 0 + runAsGroup: 0 + retentionPolicy: + name: 'keep-last-5' + keepLast: 5 + prune: true +``` + +Here, +- `spec.repository` refers to the Repository object gcs-repo that holds backend information. +- `spec.schedule` is a cron expression that indicates `BackupSession` will be created at 5 minute interval. +- `spec.target.ref` refers to the `AppBinding` of the `VaultServer`. + +Let’s create the BackupConfiguration crd we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/backup-restore/backup-configuration.yaml +``` + +#### Verify Backup Setup Successful + +If everything goes well, the phase of the BackupConfiguration should be Ready. +The Ready phase indicates that the backup setup is successful. Let’s verify the Phase of the +BackupConfiguration, + +```bash +$ kubectl get backupconfiguration -n demo + +NAME TASK SCHEDULE PAUSED PHASE AGE +demo-backup vault-backup-1.10.3 */5 * * * * true Ready 92m + +``` + +#### Verify Cronjob + +```bash +$ kubectl get cronjob -n demo + +NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE +stash-trigger--demo-backup */5 * * * * True 0 93m +``` + +#### Wait for BackupSession + +The demo-backup CronJob will trigger a backup on each scheduled slot by creating a BackupSession crd. +The sidecar container watches for the BackupSession crd. When it finds one, it will take backup immediately. + +Wait for the next schedule for backup. Run the following command to watch BackupSession crd, + +```bash +kubectl get backupsession -n demo + +NAME INVOKER-TYPE INVOKER-NAME PHASE DURATION AGE +demo-backup-s2kwg BackupConfiguration demo-backup Succeeded 39s 58s +``` + +#### Verify Backup + +Once a backup is complete, Stash will update the respective Repository crd to reflect the backup. +Check that the repository gcs-repo has been updated by the following command, + +```bash +kubectl get repository -n demo + +NAME INTEGRITY SIZE SNAPSHOT-COUNT LAST-SUCCESSFUL-BACKUP AGE +gcp-demo-repo true 75.867 KiB 1 11m 11m +``` + + +Now, if we navigate to the GCS bucket, we are going to see backed up data is uploaded successfully: + +
+ Vault Backup +
Fig: Vault Backup
+
+ + +Up next: +- Read about step-by-step Restore procedure [here](/docs/v2025.11.21/guides/backup-restore/restore) \ No newline at end of file diff --git a/content/docs/v2025.11.21/guides/backup-restore/overview.md b/content/docs/v2025.11.21/guides/backup-restore/overview.md new file mode 100644 index 000000000..53752e460 --- /dev/null +++ b/content/docs/v2025.11.21/guides/backup-restore/overview.md @@ -0,0 +1,201 @@ +--- +title: Vault Backup Restore Overview +menu: + docs_v2025.11.21: + identifier: overview-backup-restore-guides + name: Overview + parent: backup-restore-guides + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Vault Backup Restore Overview + +`Vault` provides a set of standard operating procedures `(SOP)` for backing up a Vault cluster. It protects your Vault cluster +against data corruption or sabotage of which Disaster Recovery Replication might not be able to protect against. + +`KubeVault` supports number of different [Storage Backend](/docs/v2025.11.21/concepts/vault-server-crds/storage/overview) types. Therefore, the exact steps to backup Vault will depend on your +selected storage backend. The two recommended storage backend types are Consul and Integrated Storage +(also known as Raft). + +`KubeVault` currently supports Backup & Restore for `Raft` storage backend. So, this document assumes that `Raft` storage backend is being used. + +## Backup & Restore process for Raft + +Your `VaultServer` must be in `Ready` state for Backup & Restore process to work. This will take the snapshot +using a consistent mode that forwards the request to the cluster leader, and the leader will verify it is still +in power before taking the snapshot. + +A simple `VaultServer` YAML with `Raft` storage backend may look like this: + +```yaml +apiVersion: kubevault.com/v1alpha2 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.10.3 + replicas: 3 + allowedSecretEngines: + namespaces: + from: All + backend: + raft: + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + terminationPolicy: WipeOut +``` + +Let's take a look at some relevant fields: + +`spec.backend` contains the Backend storage information, `Raft` in this case: + +```yaml +backend: + raft: + storage: + resources: + requests: + storage: 1Gi + storageClassName: standard +``` + +`spec.unsealer` contains `VaultServer` unsealing option. In this case which is `Kubernetes` Secret. So, on Vault deployment +a Secret will be created on the same namespace, which will create the Vault unseal-keys & root-token. + +```yaml +unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys +``` + +`KubeVault` operator will create an `AppBinding` with all the necessary information for backup & restore. +`AppBinding` has the information about the Unsealer option of the `VaultServer`. During the Backup, +Vault `unseal-keys` & `root-token` will also be backed-up for the completeness of the Backup process. + +`KubeVault` created `AppBinding` YAML may look like this: + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault + namespace: demo +spec: + appRef: + apiGroup: kubevault.com + kind: VaultServer + name: vault + namespace: demo + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + backend: raft + backupTokenSecretRef: + name: vault-backup-token + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + stash: + addon: + backupTask: + name: vault-backup-1.10.3 + params: + - name: keyPrefix + value: k8s.kubevault.com.demo.vault + restoreTask: + name: vault-restore-1.10.3 + params: + - name: keyPrefix + value: k8s.kubevault.com.demo.vault + unsealer: + mode: + kubernetesSecret: + secretName: vault-keys + secretShares: 5 + secretThreshold: 3 + vaultRole: vault-policy-controller +``` + +Read more about `AppBinding` [here](/docs/v2025.11.21/concepts/vault-server-crds/appbinding). + +Here: +- `spec.parameters.stash` section contains the stash parameters for Backup & Restore tasks. +- `spec.parameters.stash.addon` contains the information about the `Task` for backup & restore. +It also contains the `params` which indicates the `keyPrefix` that is prepended with the name of vault `unseal-keys` & `root-token`, e.g. `k8s.kubevault.com.demo.vault-root-token`, +`k8s.kubevault.com.demo.vault-root-token-unseal-key-0`, `k8s.kubevault.com.demo.vault-root-token-unseal-key-1`, etc. + +```yaml +stash: + addon: + backupTask: + name: vault-backup-1.10.3 + params: + - name: keyPrefix + value: k8s.kubevault.com.demo.vault + restoreTask: + name: vault-restore-1.10.3 + params: + - name: keyPrefix + value: k8s.kubevault.com.demo.vault +``` + + +`KubeVault` operator will create a `K8s Secret` containing a `token` during the Vault deployment, which contains the necessary permission +for the Backup & Restore process. This information is available in the `AppBinding` created by the operator. AppBinding +`spec.parameters.backupTokenSecretRef` contains the reference of that secret. + +```yaml +spec: + parameters: + backupTokenSecretRef: + name: vault-backup-token + +``` + +A sample policy document / permission may look like this: + +```hcl +path "sys/storage/raft/snapshot" { + capabilities = ["read"] +} + +path "sys/storage/raft/snapshot-force" { + capabilities = ["read"] +} +``` + +If your `Vault` deployment isn't managed by `KubeVault`, then you'll need to create the `AppBinding` & `Secret` containing +the permissions required for backup & restore separately. + +Up next: +- Read about step-by-step Backup procedure [here](/docs/v2025.11.21/guides/backup-restore/backup) +- Read about step-by-step Restore procedure [here](/docs/v2025.11.21/guides/backup-restore/restore) + diff --git a/content/docs/v2025.11.21/guides/backup-restore/restore.md b/content/docs/v2025.11.21/guides/backup-restore/restore.md new file mode 100644 index 000000000..b585b4e6a --- /dev/null +++ b/content/docs/v2025.11.21/guides/backup-restore/restore.md @@ -0,0 +1,188 @@ +--- +title: Vault Backup Restore Overview +menu: + docs_v2025.11.21: + identifier: restore-backup-restore-guides + name: Restore + parent: backup-restore-guides + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Restore Vault Cluster using Stash + +This guide will show you how you can restore your Vault cluster with Stash. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the `kubectl` command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using Minikube. +- Install KubeVault in your cluster following the steps [here](/docs/v2025.11.21/setup/README). +- Install Stash in your cluster following the steps [here](https://stash.run/docs/latest/setup/). +- Install Stash `kubectl` plugin following the steps [here](https://stash.run/docs/latest/setup/install/kubectl-plugin/). +- If you are not familiar with how Stash backup and restore Vault cluster, please check the following concept section [here](/docs/v2025.11.21/concepts/backup-restore/overview). + +You have to be familiar with following custom resources: + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/appbinding) +- [Function](https://stash.run/docs/latest/concepts/crds/function/) +- [Task](https://stash.run/docs/latest/concepts/crds/task/) +- [BackupConfiguration](https://stash.run/docs/latest/concepts/crds/backupconfiguration/) +- [RestoreSession](https://stash.run/docs/latest/concepts/crds/restoresession/) + +You may restore a Vault snapshot into the same Vault cluster from which snapshot was taken or into a +completely new Vault deployment. + +### Restore Snapshot for same Vault + +Follow this guideline, if you want to restore a snapshot into the same Vault cluster. +Vault cluster must be `Initialized` & `Unsealed` before trying to restore the snapshot. + +Then, simply you can create a `RestoreSession` to restore the snapshot. A sample `RestoreSession` YAML may look like this: + +```yaml +apiVersion: stash.appscode.com/v1beta1 +kind: RestoreSession +metadata: + name: vault-restore-session + namespace: demo +spec: + repository: + name: gcp-demo-repo + target: + ref: + apiVersion: appcatalog.appscode.com/v1alpha1 + kind: AppBinding + name: vault + runtimeSettings: + container: + securityContext: + runAsUser: 0 + runAsGroup: 0 + rules: + - snapshots: [latest] + +``` + +#### Create RestoreSession + +Create the `RestoreSession` for restore the snapshot: + +```yaml +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/backup-restore/restore-session.yaml +``` + +Now, wait for `RestoreSession` to succeed: + +```bash +$ kubectl get restoresession -n demo + +NAME REPOSITORY PHASE DURATION AGE +vault-restore-session gcp-demo-repo Succeeded 19s 27s + +``` + +Once the `RestoreSession` is Succeeded, snapshot will be successfully restored into the Vault cluster. + +### Restore Snapshot for different Vault + +Follow this guideline, if you want to restore a snapshot into a different Vault cluster. + +You need to deploy the new `Vault` cluster & it must be `Initialized` & `Unsealed`. This `Vault` has a +completely different set of `unseal keys` & `root token` from the `Vault` from which the snapshot was taken. + +`Vault` snapshot carries the signature of `unseal keys`. So, we need to restore the snapshot forcefully & to bypass +this, we need to modify our restore `function` accordingly. A `Function` CRD may look like this: + +```yaml +apiVersion: stash.appscode.com/v1beta1 +kind: Function +metadata: + name: vault-restore-1.10.3 +spec: + args: + - restore-vault + - --provider=${REPOSITORY_PROVIDER:=} + - --bucket=${REPOSITORY_BUCKET:=} + - --endpoint=${REPOSITORY_ENDPOINT:=} + - --region=${REPOSITORY_REGION:=} + - --path=${REPOSITORY_PREFIX:=} + - --storage-secret-name=${REPOSITORY_SECRET_NAME:=} + - --storage-secret-namespace=${REPOSITORY_SECRET_NAMESPACE:=} + - --scratch-dir=/tmp + - --enable-cache=${ENABLE_CACHE:=true} + - --max-connections=${MAX_CONNECTIONS:=0} + - --wait-timeout=${waitTimeout:=300} + - --hostname=${HOSTNAME:=} + - --source-hostname=${SOURCE_HOSTNAME:=} + - --interim-data-dir=${INTERIM_DATA_DIR} + - --namespace=${NAMESPACE:=default} + - --appbinding=${TARGET_NAME:=} + - --appbinding-namespace=${TARGET_NAMESPACE:=} + - --snapshot=${RESTORE_SNAPSHOTS:=} + - --vault-args=${args:=} + - --output-dir=${outputDir:=} + - --license-apiservice=${LICENSE_APISERVICE:=} + - --force=${force:=false} + - --key-prefix=${keyPrefix:=} + - --old-key-prefix=${oldKeyPrefix:=} + image: stashed/stash-vault:1.10.3 +``` + +Let's take a look at some of the more relevant flags, that we can set to override the existing flags: + +```bash +- --force=${force:=false} +- --key-prefix=${keyPrefix:=} +- --old-key-prefix=${oldKeyPrefix:=} +``` + +By default, the `--force` flag is `false`, so in order to restoring the snapshot into a differnt Vault cluster, +this must be set to `true`. + +Moreover, once the snapshot will be restored, the newly `Vault` will be expecting the older `unseal keys` to unseal itself & +the new `unseal keys` will not be required/valid anymore. So, we'll also migrate the older `unseal keys` & `root token` in place of +the new `unseal keys` & `root token`. + +Since, `Stash` will also take backup of the Vault `unseal keys` & `root token` along with the snapshot, we can get the +older `unseal keys` & `root token`. To correctly get those, we must set the `--old-key-prefix` flag properly. + +```bash +- --force=${force:=true} +- --key-prefix=${keyPrefix:=} +- --old-key-prefix=${oldKeyPrefix:=} +``` + +`KeyPrefix` will be generated by the following structure by `KubeVault` operator: +`k8s.{kubevault.com or cluster UID}.{vault-namespace}.{vault-name}`. In case of Vault deployment using Vault Helm-chart +or if you want to save it with a different prefix, you need to override the `KeyPrefix` section. + +The default `key-prefix`, associated `Task` for `Backup` & `Restore` can be found in the Vault `AppBinding` YAML: + +```yaml +stash: + addon: + backupTask: + name: vault-backup-1.10.3 + params: + - name: keyPrefix + value: k8s.kubevault.com.demo.vault + restoreTask: + name: vault-restore-1.10.3 + params: + - name: keyPrefix + value: k8s.kubevault.com.demo.vault + +``` + +Now, we need to apply the changes in our restore `Function` CRD. Now, we can create the `RestoreSession` +to restore the Vault cluster by the similar way mentioned above. + +Up next: +- Read about step-by-step Backup procedure [here](/docs/v2025.11.21/guides/backup-restore/backup) \ No newline at end of file diff --git a/content/docs/v2025.11.21/guides/monitoring/_index.md b/content/docs/v2025.11.21/guides/monitoring/_index.md new file mode 100644 index 000000000..b127b6531 --- /dev/null +++ b/content/docs/v2025.11.21/guides/monitoring/_index.md @@ -0,0 +1,17 @@ +--- +title: Guides Monitoring +menu: + docs_v2025.11.21: + identifier: monitoring-guides + name: Monitoring + parent: guides + weight: 40 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/monitoring/overview.md b/content/docs/v2025.11.21/guides/monitoring/overview.md new file mode 100644 index 000000000..9da896346 --- /dev/null +++ b/content/docs/v2025.11.21/guides/monitoring/overview.md @@ -0,0 +1,86 @@ +--- +title: Monitoring Overview | KubeVault +description: A General Overview of Monitoring KubeVault Components +menu: + docs_v2025.11.21: + identifier: overview-monitoring + name: Overview + parent: monitoring-guides + weight: 5 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Monitoring KubeVault Components + +KubeVault operator has native support for monitoring via [Prometheus](https://prometheus.io/). You can use builtin [Prometheus](https://github.com/prometheus/prometheus) scraper or [Prometheus Operator](https://github.com/coreos/prometheus-operator) to monitor KubeVault operator. This tutorial will show you how this monitoring works with KubeVault operator and how to enable them. + +## Vault Server Metrics + +By default the KubeVault operator will configure each vault pod to publish [statsd](https://www.vaultproject.io/docs/configuration/telemetry.html) metrics. The KubeVault operator runs a [statsd-exporter](https://github.com/kubevault/vault_exporter) container as sidecar to convert and expose those metrics in Prometheus format. Following diagram shows the logical structure of KubeVault operator monitoring flow. + +

+  Monitoring Structure +

+ +Each pod provides metrics at `/metrics` endpoint on port `9102`. Following metrics are available for Vault server. + +- vault_audit +- vault_audit_file +- vault_barrier +- vault_core +- vault_runtime +- vault_expire +- vault_merkle_flushdirty +- vault_merkle_savecheckpoint +- vault_policy +- vault_token +- vault_wal +- vault_rollback_attempt +- logshipper_streamWALs +- replication +- database +- database_error +- database_name +- database_named_error +- vault_storage_backend +- vault_provider_lock +- vault_consul +- vault_route +- vault_expire_num_leases +- vault_runtime_alloc_bytes +- vault_runtime_free_count +- vault_runtime_heap_objects +- vault_runtime_malloc_count +- vault_runtime_num_goroutines +- vault_runtime_sys_bytes +- vault_runtime_total_gc_pause_ns +- vault_runtime_total_gc_runs +- vault_runtime_gc_pause_ns + +## KubeVault Operator Metrics + +You can enable monitoring for the KubeVault operator while installing or upgrading the operator. You can chose which monitoring agent to use for monitoring. KubeVault operator will configure respective resources accordingly. Here are the list of available flags and their usage: + +| Script Flag | Helm Values | Acceptable Values | Default | Description | +| ------------------------ | ---------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--monitoring-agent` | `monitoring.agent` | `prometheus.io/builtin` or `prometheus.io/coreos-operator` | `none` | Specify which monitoring agent to use for monitoring KubeVault operator. | +| `--monitor-operator` | `monitoring.operator` | `true` or `false` | `false` | Specify whether to monitor KubeVault operator. | +| `--prometheus-namespace` | `monitoring.prometheus.namespace` | any namespace | same namespace as KubeVault operator | Specify the namespace where Prometheus server is running or will be deployed | +| `--servicemonitor-label` | `monitoring.serviceMonitor.labels` | any label | For Helm installation, `app: ` and `release: `. For script installation, `app: vault-operator` | Specify the labels for ServiceMonitor. Prometheus crd will select ServiceMonitor using these labels. Only usable when monitoring agent is `prometheus.io/coreos-operator`. | + +## Next Steps + +- Learn how to monitor Vault server using built-in Prometheus from [here](/docs/v2025.11.21/guides/monitoring/vault-server/builtin). +- Learn how to monitor Vault server using CoreOS Prometheus operator from [here](/docs/v2025.11.21/guides/monitoring/vault-server/coreos). +- Learn how to use Grafana dashboard to visualize monitoring data from [here](/docs/v2025.11.21/guides/monitoring/vault-server/grafana). +- Learn how to monitor KubeVault operator using built-in Prometheus from [here](/docs/v2025.11.21/guides/monitoring/vault-operator/builtin). +- Learn how to monitor KubeVault operator using CoreOS Prometheus operator from [here](/docs/v2025.11.21/guides/monitoring/vault-operator/coreos). diff --git a/content/docs/v2025.11.21/guides/monitoring/vault-operator/_index.md b/content/docs/v2025.11.21/guides/monitoring/vault-operator/_index.md new file mode 100755 index 000000000..7ed202510 --- /dev/null +++ b/content/docs/v2025.11.21/guides/monitoring/vault-operator/_index.md @@ -0,0 +1,17 @@ +--- +title: Monitoring KubeVault operator +menu: + docs_v2025.11.21: + identifier: vault-operator-monitoring + name: KubeVault operator + parent: monitoring-guides + weight: 20 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/monitoring/vault-operator/builtin.md b/content/docs/v2025.11.21/guides/monitoring/vault-operator/builtin.md new file mode 100644 index 000000000..37264628a --- /dev/null +++ b/content/docs/v2025.11.21/guides/monitoring/vault-operator/builtin.md @@ -0,0 +1,308 @@ +--- +title: Monitor KubeVault operator using Builtin Prometheus Discovery +menu: + docs_v2025.11.21: + identifier: builtin-prometheus-vault-operator-monitoring + name: Builtin Prometheus + parent: vault-operator-monitoring + weight: 20 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Monitor KubeVault operator with builtin Prometheus + +This tutorial will show you how to configure builtin [Prometheus](https://github.com/prometheus/prometheus) scraper to monitor KubeVault operator. + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). + +To keep Prometheus resources isolated, we are going to use a separate namespace to deploy Prometheus server. + +```bash +$ kubectl create ns monitoring +namespace/monitoring created +``` + +## Enable Monitoring in KubeVault operator + +Enable Prometheus monitoring using `prometheus.io/builtin` annotations while install KubeVault operator. To know details about how to enable monitoring see [here](/docs/v2025.11.21/guides/monitoring/overview#how-to-enable-monitoring) + +Here, we are going to enable monitoring for `operator` metrics. + +**Using Helm 3:** + +```bash +$ helm install kubevault oci://ghcr.io/appscode-charts/kubevault \ + --version {{< param "info.version" >}} \ + --namespace kubevault --create-namespace \ + --set monitoring.agent=prometheus.io/builtin \ + --set monitoring.operator=true \ + --set monitoring.prometheus.namespace=monitoring +``` + +**Using YAML (with Helm 3):** + +```bash +$ helm template kubevault oci://ghcr.io/appscode-charts/kubevault \ + --version {{< param "info.version" >}} \ + --namespace kubevault --create-namespace \ + --no-hooks \ + --set monitoring.agent=prometheus.io/builtin \ + --set monitoring.operator=true \ + --set monitoring.prometheus.namespace=monitoring | kubectl apply -f - +``` + +This will add necessary annotations to `vault-operator` service. Prometheus server will scrap metrics using those annotations. Let's check which annotations are added to the service, + +```yaml +$ kubectl get svc vault-operator -n kube-system -o yaml +apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/path: /metrics + prometheus.io/port: "8443" + prometheus.io/scheme: https + prometheus.io/scrape: "true" + creationTimestamp: "2018-12-26T06:12:51Z" + labels: + app: vault-operator + chart: vault-operator-{{< param "info.version" >}} + heritage: Tiller + release: vault-operator + name: vault-operator + namespace: kube-system + resourceVersion: "10030" + selfLink: /api/v1/namespaces/kube-system/services/vault-operator + uid: 469d2c8f-08d5-11e9-852c-080027857726 +spec: + clusterIP: 10.110.168.15 + ports: + - name: api + port: 443 + protocol: TCP + targetPort: 8443 + selector: + app: vault-operator + release: vault-operator + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} +``` + +Here, `prometheus.io/scrape: "true"` annotation indicates that Prometheus should scrap metrics for this service. + +The following three annotations point to api endpoints which provides operator specific metrics. + +```bash +prometheus.io/path: /metrics +prometheus.io/port: "8443" +prometheus.io/scheme: https +``` + +Now, we are ready to configure our Prometheus server to scrap those metrics. + +## Deploy Prometheus Server + +We have deployed KubeVault operator in `kube-system` namespace. KubeVault operator exports operator metrics via TLS secured `api` endpoint. So, Prometheus server need to provide certificate while scraping metrics from this endpoint. KubeVault operator has created a secret named `vault-operator-apiserver-cert` with this certificate in `monitoring` namespaces as we have specified that we are going to deploy Prometheus in that namespace through `--prometheus-namespace` or `monitoring.prometheus.namespace` flag. We have to mount this secret in Prometheus deployment. + +Let's check `vault-operator-apiserver-cert` secret has been created in `monitoring` namespace. + +```bash +$ kubectl get secrets -n monitoring -l=app.kubernetes.io/name=vault-operator +NAME TYPE DATA AGE +vault-operator-apiserver-cert kubernetes.io/tls 2 107m +``` + +#### Create `RBAC` + +If you are using a `RBAC` enabled cluster, you have to provide necessary `RBAC` permissions for Prometheus. Following [this](https://github.com/appscode/third-party-tools/blob/master/monitoring/prometheus/builtin/README.md#deploy-prometheus-server), let's create `RBAC` stuffs for Prometheus by running: + +```bash +$ kubectl apply -f https://github.com/appscode/third-party-tools/raw/master/monitoring/prometheus/builtin/artifacts/rbac.yaml +clusterrole.rbac.authorization.k8s.io/prometheus created +serviceaccount/prometheus created +clusterrolebinding.rbac.authorization.k8s.io/prometheus created +``` +> YAML for RBAC resources can be found [here](https://github.com/appscode/third-party-tools/blob/master/monitoring/prometheus/builtin/artifacts/rbac.yaml). + +#### Create `ConfigMap` + +As we are monitoring KubeVault operator, we should follow [this](https://github.com/appscode/third-party-tools/blob/master/monitoring/prometheus/builtin/README.md#kubernetes-apiservers) to create a ConfigMap. Bellow the YAML of ConfigMap that we are going to create in this tutorial + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-config + labels: + name: prometheus-config + namespace: monitoring +data: + prometheus.yml: |- + global: + scrape_interval: 5s + evaluation_interval: 5s + scrape_configs: + - job_name: 'vault-apiservers' + honor_labels: true + kubernetes_sd_configs: + - role: endpoints + # Kubernetes apiserver serve metrics on a TLS secure endpoints. so, we have to use "https" scheme + scheme: https + # we have to provide certificate to establish tls secure connection + tls_config: + ca_file: /etc/prometheus/secret/vault-operator-apiserver-cert/tls.crt + server_name: vault-operator.kube-system.svc + # bearer_token_file is required for authorizating prometheus server to Kubernetes apiserver + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + + relabel_configs: + - source_labels: [__meta_kubernetes_service_label_app] + separator: ; + regex: vault-operator + replacement: $1 + action: keep + - source_labels: [__meta_kubernetes_endpoint_address_target_kind, __meta_kubernetes_endpoint_address_target_name] + separator: ; + regex: Node;(.*) + target_label: node + replacement: ${1} + action: replace + - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: kube-system;vault-operator;api + - separator: ; + regex: (.*) + target_label: endpoint + replacement: api + action: replace + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*) + target_label: job + replacement: ${1} + action: replace +``` + +Look at the `tls_config` field of `vault-apiservers` job. We have provided certificate file through `ca_file` field. This certificate comes from `vault-operator-apiserver-cert` that we are going to mount in Prometheus deployment. Here, `server_name` is used to verify hostname. In our case, the certificate is valid for hostname server and `vault-operator.kube-system.svc`. + +In `relabel_configs` section we added `..svc:443` as the value of `replacement`. + +Let's create the ConfigMap we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/monitoring/vault-operator/prom-server-conf.yaml +configmap/prometheus-config created +``` + +#### Deploy Prometheus + +Now, we are ready to deploy Prometheus server. YAML for the deployment that we are going to create for Prometheus is shown below. + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: prometheus-demo + name: prometheus + namespace: monitoring +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + spec: + containers: + - args: + - --config.file=/etc/prometheus/prometheus.yml + - --storage.tsdb.path=/prometheus/ + image: prom/prometheus:v2.5.0 + imagePullPolicy: IfNotPresent + name: prometheus + ports: + - containerPort: 9090 + protocol: TCP + volumeMounts: + - mountPath: /etc/prometheus/ + name: prometheus-config + - mountPath: /prometheus/ + name: prometheus-storage + - mountPath: /etc/prometheus/secret/vault-operator-apiserver-cert + name: vault-operator-apiserver-cert + serviceAccountName: prometheus + volumes: + - configMap: + defaultMode: 420 + name: prometheus-config + name: prometheus-config + - emptyDir: {} + name: prometheus-storage + - name: vault-operator-apiserver-cert + secret: + defaultMode: 420 + secretName: vault-operator-apiserver-cert + items: + - path: tls.crt + key: tls.crt +``` + +Notice that, we have mounted vault-operator-apiserver-cert secret as a volume at `/etc/prometheus/secret/vault-operator-apiserver-cert` directory. + +Now, let's create the deployment, + +```bash +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/monitoring/vault-operator/prom-builtin-deployment.yaml +deployment.apps "prometheus" deleted +``` + +#### Verify Monitoring Metrics + +Prometheus server is running on port 9090. We are going to use [port forwarding](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) to access Prometheus dashboard. Run following commands on a separate terminal, + +```bash +$ kubectl get pod -n monitoring -l=app=prometheus +NAME READY STATUS RESTARTS AGE +prometheus-8568c86d86-vpzx5 1/1 Running 0 102s + +$ kubectl port-forward -n monitoring prometheus-8568c86d86-vpzx5 9090 +Forwarding from 127.0.0.1:9090 -> 9090 +Forwarding from [::1]:9090 -> 9090 +``` + +Now, we can access the dashboard at localhost:9090. Open [http://localhost:9090](http://localhost:9090) in your browser. You should see the configured jobs as target and they are in UP state which means Prometheus is able collect metrics from them. + +

+ +   builtin-prom-vault + +

+ +## Cleaning up + +To uninstall Prometheus server follow [this](https://github.com/appscode/third-party-tools/blob/master/monitoring/prometheus/builtin/README.md#cleanup) + +To uninstall KubeVault operator follow [this](https://github.com/kubevault/kubevault/blob/master/docs/setup/operator/uninstall.md#uninstall-vault-operator) + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns monitoring +``` + diff --git a/content/docs/v2025.11.21/guides/monitoring/vault-operator/coreos.md b/content/docs/v2025.11.21/guides/monitoring/vault-operator/coreos.md new file mode 100644 index 000000000..80604d63e --- /dev/null +++ b/content/docs/v2025.11.21/guides/monitoring/vault-operator/coreos.md @@ -0,0 +1,210 @@ +--- +title: Monitor KubeVault operator using Prometheus Operator +menu: + docs_v2025.11.21: + identifier: coreos-vault-operator-monitoring + name: Prometheus Operator + parent: vault-operator-monitoring + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Monitoring KubeVault operator Using Prometheus Operator + +CoreOS [prometheus-operator](https://github.com/coreos/prometheus-operator) provides simple and Kubernetes native way to deploy and configure Prometheus server. This tutorial will show you how to use CoreOS Prometheus operator for monitoring KubeVault operator. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). + +- To keep Prometheus resources isolated, we are going to use a separate namespace to deploy Prometheus operator and respective resources. + +```bash +$ kubectl create ns monitoring +namespace/monitoring created +``` + +- We need a CoreOS prometheus-operator instance running. If you already don't have a running instance, deploy one following the docs from [here](https://github.com/appscode/third-party-tools/blob/master/monitoring/prometheus/coreos-operator/README.md). + +## Enable Monitoring in KubeVault operator + +Enable Prometheus monitoring using `prometheus.io/coreos-operator` agent while installing KubeVault operator. To know details about how to enable monitoring see [here](/docs/v2025.11.21/guides/monitoring/overview#how-to-enable-monitoring) + +Here, we are going to enable monitoring for `operator` metrics. + +**Using Helm 3:** + +```bash +$ helm install kubevault oci://ghcr.io/appscode-charts/kubevault \ + --version {{< param "info.version" >}} \ + --namespace kubevault --create-namespace \ + --set monitoring.agent=prometheus.io/coreos-operator \ + --set monitoring.operator=true \ + --set monitoring.prometheus.namespace=monitoring \ + --set monitoring.serviceMonitor.labels.k8s-app=prometheus +``` + +**Using YAML (with Helm 3):** + +```bash +$ helm template kubevault oci://ghcr.io/appscode-charts/kubevault \ + --version {{< param "info.version" >}} \ + --namespace kubevault --create-namespace \ + --no-hooks \ + --set monitoring.agent=prometheus.io/coreos-operator \ + --set monitoring.operator=true \ + --set monitoring.prometheus.namespace=monitoring \ + --set monitoring.serviceMonitor.labels.k8s-app=prometheus | kubectl apply -f - +``` + +This will create a `ServiceMonitor` crd with name `vault-operator-servicemonitor` in `monitoring` namespace for monitoring endpoints of `vault-operator` service. This ServiceMonitor will have label `k8s-app: prometheus` provided by `--servicemonitor-label` flag. This label will be used by Prometheus crd to select this ServiceMonitor. + +Let's check the ServiceMonitor crd using following command, + +```yaml +$ kubectl get servicemonitors -n monitoring vault-operator-servicemonitor -o yaml +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + creationTimestamp: "2018-12-26T11:13:25Z" + generation: 1 + labels: + k8s-app: prometheus + name: vault-operator-servicemonitor + namespace: monitoring + resourceVersion: "32902" + selfLink: /apis/monitoring.coreos.com/v1/namespaces/monitoring/servicemonitors/vault-operator-servicemonitor + uid: 438a7cb5-08ff-11e9-852c-080027857726 +spec: + endpoints: + - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + port: api + scheme: https + tlsConfig: + caFile: /etc/prometheus/secrets/vault-operator-apiserver-cert/tls.crt + serverName: vault-operator.kube-system.svc + namespaceSelector: + matchNames: + - kube-system + selector: + matchLabels: + app: vault-operator + release: vault-operator +``` + +Here, `api` endpoint exports operator metrics. + +KubeVault operator exports operator metrics via TLS secured `api` endpoint. So, Prometheus server need to provide certificate while scraping metrics from this endpoint. KubeVault operator has created a secret named `vault-operator-apiserver-certs` with this certificate in `monitoring` namespace as we have specified that we are going to deploy Prometheus in that namespace through `--prometheus-namespace` flag. We have to specify this secret in Prometheus crd through `spec.secrets` field. Prometheus operator will mount this secret at `/etc/prometheus/secrets/vault-operator-apiserver-cert` directory of respective Prometheus pod. So, we need to configure `tlsConfig` field to use that certificate. Here, `caFile` indicates the certificate to use and serverName is used to verify hostname. In our case, the certificate is valid for hostname server and `vault-operator.kube-system.svc`. + +Let's check secret vault-operator-apiserver-cert has been created in monitoring namespace. + +```bash +$ kubectl get secret -n monitoring -l=app.kubernetes.io/name=vault-operator +NAME TYPE DATA AGE +vault-operator-apiserver-cert kubernetes.io/tls 2 8m27s +``` + +Also note that, there is a bearerTokenFile field. This file is token for the serviceaccount that will be created while creating RBAC stuff for Prometheus crd. This is required for authorizing Prometheus to scrape KubeVault operator API server. + +Now, we are ready to deploy Prometheus server. + +## Deploy Prometheus Server + +In order to deploy Prometheus server, we have to create Prometheus crd. Prometheus crd defines a desired Prometheus server setup. For more details about Prometheus crd, please visit [here](https://github.com/coreos/prometheus-operator/blob/master/Documentation/design.md#prometheus). + +If you are using a RBAC enabled cluster, you have to give necessary permissions to Prometheus. Check the documentation to see required RBAC permission from [here](https://github.com/appscode/third-party-tools/blob/master/monitoring/prometheus/coreos-operator/README.md#deploy-prometheus-server). + +#### Create Prometheus: + +Below is the YAML of Prometheus crd that we are going to create for this tutorial, + +```yaml +apiVersion: monitoring.coreos.com/v1 +kind: Prometheus +metadata: + name: prometheus + namespace: monitoring + labels: + k8s-app: prometheus +spec: + replicas: 1 + serviceAccountName: prometheus + serviceMonitorSelector: + matchLabels: + k8s-app: prometheus + secrets: + - vault-operator-apiserver-cert + resources: + requests: + memory: 400Mi +``` + +Here, `spec.serviceMonitorSelector` is used to select the ServiceMonitor crd that is created by KubeVault operator. We have provided `vault-operator-apiserver-cert` secret in `spec.secrets` field. This will be mounted in Prometheus pod. + +Let's create the Prometheus object we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/monitoring/vault-operator/prom-coreos-crd.yaml +prometheus.monitoring.coreos.com/prometheus created +``` + +Prometheus operator watches for Prometheus `crd`. Once a Prometheus crd is created, Prometheus operator generates respective configuration and creates a `StatefulSet` to run Prometheus server. + +Let's check `StatefulSet` has been created, + +```bash +$ kubectl get statefulset -n monitoring +NAME READY AGE +prometheus-prometheus 1/1 31m +``` + +Check StatefulSet's pod is running, + +```bash +$ kubectl get pod prometheus-prometheus-0 -n monitoring +NAME READY STATUS RESTARTS AGE +prometheus-prometheus-0 3/3 Running 1 31m +``` + +Now, we are ready to access Prometheus dashboard. + +#### Verify Monitoring Metrics + +Prometheus server is running on port 9090. We are going to use [port forwarding](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) to access Prometheus dashboard. Run following commands on a separate terminal, + +```bash +$ kubectl port-forward -n monitoringprometheus-prometheus-0 9090 +Forwarding from 127.0.0.1:9090 -> 9090 +Forwarding from [::1]:9090 -> 9090 +``` + +Now, we can access the dashboard at localhost:9090. Open [http://localhost:9090](http://localhost:9090) in your browser. You should see the configured jobs as target and they are in UP state which means Prometheus is able collect metrics from them. + +

+ +   builtin-prom-vault + +

+ +## Cleaning up + +To uninstall KubeVault operator follow [this](https://github.com/kubevault/kubevault/blob/master/docs/setup/operator/uninstall.md#uninstall-vault-operator). + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +# cleanup Prometheus resources +kubectl delete -n monitoring prometheus prometheus +kubectl delete -n monitoring secret vault-operator-apiserver-cert + +$ kubectl delete ns monitoring +``` \ No newline at end of file diff --git a/content/docs/v2025.11.21/guides/monitoring/vault-server/_index.md b/content/docs/v2025.11.21/guides/monitoring/vault-server/_index.md new file mode 100755 index 000000000..f5d84a526 --- /dev/null +++ b/content/docs/v2025.11.21/guides/monitoring/vault-server/_index.md @@ -0,0 +1,17 @@ +--- +title: Monitoring Vault Server +menu: + docs_v2025.11.21: + identifier: vault-server-monitoring + name: Vault Server + parent: monitoring-guides + weight: 10 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/monitoring/vault-server/builtin.md b/content/docs/v2025.11.21/guides/monitoring/vault-server/builtin.md new file mode 100644 index 000000000..eae2896db --- /dev/null +++ b/content/docs/v2025.11.21/guides/monitoring/vault-server/builtin.md @@ -0,0 +1,229 @@ +--- +title: Monitor Vault Server using Builtin Prometheus Discovery +menu: + docs_v2025.11.21: + identifier: builtin-prometheus-vault-server-monitoring + name: Builtin Prometheus + parent: vault-server-monitoring + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Monitor Vault server with builtin Prometheus scraper + +This tutorial will show you how to configure builtin [Prometheus](https://github.com/prometheus/prometheus) scraper to monitor Vault server provisioned by the KubeVault operator. + +The prometheus server is needed to configure so that it can discover endpoints of Kubernetes services. If a Prometheus server is already running in cluster and if it is configured in a way that it can discover service endpoints, no extra configuration will be needed.Otherwise, read this [tutorial](https://github.com/appscode/third-party-tools/tree/master/monitoring/prometheus/builtin/README.md) to deploy a Prometheus server with appropriate configuration. + +Create the following configmap with Prometheus configuration and pass it to a Prometheus server. + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-server-conf + labels: + name: prometheus-server-conf + namespace: demo +data: + prometheus.yml: |- + global: + scrape_interval: 5s + evaluation_interval: 5s + scrape_configs: + - job_name: 'kubernetes-service-endpoints' + + kubernetes_sd_configs: + - role: endpoints + + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name +``` + +You can create above ConfigMap by running + +```bash +$ kubectl create -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/monitoring/vault-server/prom-server-conf.yaml +configmap/prometheus-server-conf created +``` + +> Note: YAML files used in this tutorial are stored in [docs/examples](/docs/v2025.11.21/examples) + +## Monitor Vault server + +To enable monitoring, configure `spec.monitor` field in a `VaultServer` custom resource. Below is an example: + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + replicas: 1 + version: 1.2.0 + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + backend: + inmem: {} + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: "WipeOut" +``` + +Here, + +- `spec.monitor` specifies that built-in [prometheus](https://github.com/prometheus/prometheus) is used to monitor this Vault server instance. +- `monitor.prometheus` specifies the information for monitoring by Prometheus. + - `prometheus.port` indicates the port for Vault statsd exporter endpoint (default is `56790`) + - `prometheus.interval` indicates the scraping interval (eg, '10s') + +Run the following command to create it. + +```bash +$ kubectl create -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/monitoring/vault-server/vault-server-builtin.yaml +vaultserver.kubevault.com/example created +``` + +KubeVault operator will configure its service once the Vault server is successfully running. + +```bash +$ kubectl get vs -n demo +NAME NODES VERSION STATUS AGE +example 1 0.11.1 Running 3h +``` + +Let's describe Service `example-stats` + +```bash +$ kubectl get svc -n demo example -o yaml +apiVersion: v1 +kind: Service +metadata: + annotations: + monitoring.appscode.com/agent: prometheus.io/builtin + prometheus.io/path: /metrics + prometheus.io/port: "9102" + prometheus.io/scrape: "true" + creationTimestamp: "2018-12-24T11:27:28Z" + labels: + app: vault + vault_cluster: example + name: example + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + controller: true + kind: VaultServer + name: example + uid: e42c20cd-076e-11e9-b586-0800274de81b + resourceVersion: "1828" + selfLink: /api/v1/namespaces/demo/services/example + uid: e5064216-076e-11e9-b586-0800274de81b +spec: + clusterIP: 10.107.246.170 + externalTrafficPolicy: Cluster + ports: + - name: client + nodePort: 31528 + port: 8200 + protocol: TCP + targetPort: 8200 + - name: cluster + nodePort: 32245 + port: 8201 + protocol: TCP + targetPort: 8201 + - name: prom-http + nodePort: 30292 + port: 9102 + protocol: TCP + targetPort: 9102 + selector: + app: vault + vault_cluster: example + sessionAffinity: None + type: NodePort +status: + loadBalancer: {} + +``` + +You can see that the service contains following annotations. + +```bash +monitoring.appscode.com/agent: prometheus.io/builtin +prometheus.io/path: /metrics +prometheus.io/port: "9102" +prometheus.io/scrape: "true" +``` + +The Prometheus server will discover the Vault service endpoint and will scrape metrics from the exporter sidecar. + +

+ +   builtin-prom-vault + +

+ +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete -n demo vs/example +$ kubectl delete ns demo +``` + diff --git a/content/docs/v2025.11.21/guides/monitoring/vault-server/coreos.md b/content/docs/v2025.11.21/guides/monitoring/vault-server/coreos.md new file mode 100644 index 000000000..b43b7bf8c --- /dev/null +++ b/content/docs/v2025.11.21/guides/monitoring/vault-server/coreos.md @@ -0,0 +1,104 @@ +--- +title: Monitor Vault Server using Prometheus Operator +menu: + docs_v2025.11.21: + identifier: coreos-vault-server-monitoring + name: Prometheus Operator + parent: vault-server-monitoring + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Monitoring Vault Server Using Prometheus Operator + +CoreOS [prometheus-operator](https://github.com/coreos/prometheus-operator) provides simple and Kubernetes native way to deploy and configure Prometheus server. This tutorial will show you how to monitor Vault server using Prometheus via Prometheus Operator). + +## Monitor Vault server + +To enable monitoring, configure `spec.monitor` field in a `VaultServer` custom resource. Below is an example: + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + replicas: 1 + version: 1.2.0 + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + - alias: stats + spec: + type: ClusterIP + backend: + inmem: {} + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: "WipeOut" +``` + +Here, + +- `monitor.agent` indicates the monitoring agent `coreos-prometheus-operator`. +- `monitor.prometheus` specifies the information for monitoring by Prometheus. + - `prometheus.namespace` specifies the namespace where ServiceMonitor is created. + - `prometheus.labels` specifies the labels applied to ServiceMonitor. + - `prometheus.port` indicates the port for Vault statsd exporter endpoint (default is `56790`) + - `prometheus.interval` indicates the scraping interval (eg, '10s') + +Now create Vault server with the monitoring spec + +```bash +$ kubectl create -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/monitoring/vault-server/vault-server-coreos.yaml + +``` + +KubeVault operator will create a ServiceMonitor object once the Vault server is successfully running. + +```bash +$ kubectl get servicemonitor -n demo +NAME AGE +vault-demo-exampleco 23s +``` + +Now, if you go the Prometheus Dashboard, you should see that this Vault endpoint as one of the targets. + +

+ +   prometheus-coreos + +

+ +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete -n demo vs/coreos-prom-postgres + +$ kubectl delete ns demo +``` \ No newline at end of file diff --git a/content/docs/v2025.11.21/guides/monitoring/vault-server/grafana.md b/content/docs/v2025.11.21/guides/monitoring/vault-server/grafana.md new file mode 100644 index 000000000..fcac99564 --- /dev/null +++ b/content/docs/v2025.11.21/guides/monitoring/vault-server/grafana.md @@ -0,0 +1,118 @@ +--- +title: Grafana dashboard for Vault Server +menu: + docs_v2025.11.21: + identifier: grafana-vault-server-monitoring + name: Grafana Dashboard + parent: vault-server-monitoring + weight: 20 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Visualize Vault server data using Grafana dashboard + +Grafana provides an elegant graphical user interface to visualize data. You can create beautiful dashboard easily with a meaningful representation of your Prometheus metrics. + +If there is no grafana instance running on your cluster, then you can [read this tutorial](https://github.com/appscode/third-party-tools/blob/master/monitoring/grafana/README.md) to deploy one. + + +## Add Prometheus Data Source + +We have to add our Prometheus server `prometheus-prometheus-0` as data source of grafana. We are going to use a `ClusterIP` service to connect Prometheus server with grafana. Let's create a service to select Prometheus server `prometheus-prometheus-0`, + +```bash +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/monitoring/vault-server/prometheus-service.yaml +service/prometheus created +``` + +Below the YAML for the service we have created above, + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: monitoring +spec: + type: ClusterIP + ports: + - name: web + port: 9090 + protocol: TCP + targetPort: 9090 + selector: + app: prometheus +``` + +Now, follow these steps to add the Prometheus server as data source of Grafana UI. + +1. From Grafana UI, go to `Configuration` option from sidebar and click on `Data Sources`. + +

+   Grafana: Data Sources +

+ +2. Then, click on `Add data source`. + +

+   Grafana: Add data source +

+ +3. Now, configure `Name`, `Type` and `URL` fields as specified below and keep rest of the configuration to their default value then click `Save&Test` button. + - *Name: Vault-Operator* (you can give any name) + - *Type: Prometheus* + - *URL: http://prometheus.monitoring.svc:9090* + (url format: http://{prometheus service name}.{namespace}.svc:{port}) + +

+   Grafana: Configure data source +

+ +Once you have added Prometheus data source successfully, you are ready to create a dashboard to visualize the metrics. + +## Import Vault server Dashboard + +Vault server comes with a pre-configured Grafana dashboard. You can download json configuration of the dashboard from [here](/docs/v2025.11.21/examples/monitoring/grafana/dashboard.json). + +Follow these steps to import the preconfigured stash dashboard, + +1. From Grafana UI, go to `Create` option from sidebar and click on `import`. + +

+   Grafana: Import dashboard +

+ +2. Then, paste `json` from [here](/docs/v2025.11.21/examples/monitoring/grafana/dashboard.json) or upload `json` configuration file of the dashboard using `Upload .json File` button. + +

+   Grafana: Provide dashboard ID +

+ +3. Now on `prometheus-infra` field, select the data source name that we have given to our Prometheus data source earlier. Then click on `Import` button. + +

+   Grafana: Select data source +

+ +Once you have imported the dashboard successfully, you will be greeted with dashboard. + +

+   Grafana: Stash dashboard +

+ + +## Cleanup +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +kubectl delete -n demo service prometheus +``` \ No newline at end of file diff --git a/content/docs/v2025.11.21/guides/platforms/_index.md b/content/docs/v2025.11.21/guides/platforms/_index.md new file mode 100755 index 000000000..dc4a2c5fd --- /dev/null +++ b/content/docs/v2025.11.21/guides/platforms/_index.md @@ -0,0 +1,17 @@ +--- +title: Platform Guides | KubeVault +menu: + docs_v2025.11.21: + identifier: platform-guides + name: Platforms + parent: guides + weight: 50 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/platforms/aks.md b/content/docs/v2025.11.21/guides/platforms/aks.md new file mode 100644 index 000000000..7c97024cd --- /dev/null +++ b/content/docs/v2025.11.21/guides/platforms/aks.md @@ -0,0 +1,366 @@ +--- +title: Deploy Vault on Azure Kubernetes Service (AKS) +menu: + docs_v2025.11.21: + identifier: aks-platform + name: AKS + parent: platform-guides + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Deploy Vault on Azure Kubernetes Service (AKS) + +Here, we are going to deploy Vault in AKS using KubeVault operator. We are going to use [Azure Storage Container](https://azure.microsoft.com/en-us/services/storage/) as Vault backend and `azureKeyVault` unsealer mode for automatically unsealing the Vault. + +## Before You Begin + +At first, you need to have an AKS cluster. If you don't already have a cluster, create one from [here](https://azure.microsoft.com/en-us/services/kubernetes-service/). + +- Install KubeVault operator in your cluster following the steps [here](/docs/v2025.11.21/setup/README). + +- You should be familiar with the following CRD: + - [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) + - [Unsealer](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/overview) + - [azureKeyVault](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/azure_key_vault) + +- You will need a storage account. Guides to create a storage account can be found [here](https://docs.microsoft.com/en-us/azure/storage/common/storage-create-storage-account#create-a-storage-account). In this tutorial, we are going to use `vaultstorageac` storage account. + +- You will need a [Azure Storage Container](https://azure.microsoft.com/en-us/services/storage/) to use it as Vault backend storage. In this tutorial, we are going to use `demo-vault` blob container in `vaultstorageac` storage account. + +- You will need a Azure Key Vault for unsealer. Guides to create key vault can be found [here](https://docs.microsoft.com/en-us/azure/key-vault/key-vault-get-started). In this tutorial, we are going to use `vault-key-store` key vault. +### Provision Cluster + +We are going to provision Kubernetes cluster using AKS. + +![aks](/docs/v2025.11.21/images/guides/provider/aks/aks.png) + +Configure `.kube/config` + +```bash +$ az aks get-credentials --resource-group vault-aks --name vault +Merged "vault" as current context in /home/ac/.kube/config +``` + +```bash +$ kubectl get pods --all-namespaces +NAMESPACE NAME READY STATUS RESTARTS AGE +kube-system heapster-5d6f9b846c-69fvm 2/2 Running 0 47m +kube-system kube-dns-v20-7c7d7d4c66-8r7st 4/4 Running 0 48m +kube-system kube-dns-v20-7c7d7d4c66-vzg6n 4/4 Running 0 48m +kube-system kube-proxy-82c8t 1/1 Running 0 45m +kube-system kube-svc-redirect-hl6gz 2/2 Running 0 45m +kube-system kubernetes-dashboard-68f468887f-5knhd 1/1 Running 1 47m +kube-system metrics-server-5cbc77f79f-jc8b4 1/1 Running 1 47m +kube-system omsagent-rs-ddc44b8cd-m42b2 1/1 Running 0 47m +kube-system omsagent-s82s2 1/1 Running 0 45m +kube-system tunnelfront-8475548867-xvddt 1/1 Running 0 47m +``` + +We are going to create a `web app/api` type Azure Active Directory Application `vault-app`. Guides to create an Azure AD application can be found [here](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal#create-an-azure-active-directory-application). We will use the application id and key of this `vault-app` as credential. We are going to give `vault-app` application access to the secret in key vault `vault-key-store`. + + ![secret access permission](/docs/v2025.11.21/images/guides/provider/aks/secret-access.png) + +### Install KubeVault operator + +See [here](/docs/v2025.11.21/setup/README). + +```bash +$ kubectl get pods -n kube-system +NAMESPACE NAME READY STATUS RESTARTS AGE +kube-system vault-operator-576b7867cb-tmz2j 1/1 Running 0 7m +``` + +### Deploy Vault + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +We will deploy `my-vault` on `demo` namespace. We will configure it for Azure Container backend. We will use `azureKeyVault` for auto initializing and unsealing. + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: my-vault + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + azure: + container: demo-vault + accountName: vaultstorageac + accountKeySecret: azure-ac-key + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + azureKeyVault: + vaultBaseURL: https://vault-key-store.vault.azure.net/ + tenantID: aaaaaaa-bbbb-ccc-dddd-eeeeeeeee + aadClientSecret: azure-ad-client-secret +``` + +Here, `spec.version` specifies the name of the [VaultServerVersion](/docs/v2025.11.21/concepts/vault-server-crds/vaultserverversion) CRD. If that does not exist, then create one. + +```bash +$ kubectl get vaultserverversions +NAME VERSION VAULT_IMAGE DEPRECATED AGE +1.2.0 1.2.0 vault:1.2.0 false 1m + +$ kubectl get vaultserverversions/1.2.0 -o yaml +apiVersion: catalog.kubevault.com/v1alpha1 +kind: VaultServerVersion +metadata: + name: 1.2.0 +spec: + version: 1.2.0 + deprecated: false + vault: + image: vault:1.2.0 + unsealer: + image: kubevault/vault-unsealer:v0.3.0 + exporter: + image: kubevault/vault-exporter:0.1.0 +``` + +`spec.backend.azure.accountKeySecret` specifies the name of the Kubernetes secret containing `vaultstorageac` storage account key. + +```bash +$ kubectl get secrets azure-ac-key -n demo -o yaml +apiVersion: v1 +data: + account_key: QW5EOHhvQ1pWZ... +kind: Secret +metadata: + name: azure-ac-key + namespace: demo +type: Opaque +``` + +`spec.unsealer.mode.azureKeyVault.aadClientSecret` specifies the name of Kubernetes secret containing credential of `vault-app` Azure AD application. + +```bash +$ kubectl get secrets azure-ad-client-secret -n demo -o yaml +apiVersion: v1 +data: + client-id: NzUw... + client-secret: clllWmNPd... +kind: Secret +metadata: + name: azure-ad-client-secret + namespace: demo +type: Opaque + +``` + +`spec.unsealer.mode.azureKeyVault.vaultBaseURL` is the DNS name of the `vault-key-store` key vault. + +![key vault](/docs/v2025.11.21/images/guides/provider/aks/key-vault.png) + +Now, we are going to create `my-vault` in `demo` namespace. + +```bash +$ cat examples/guides/provider/aks/my-vault.yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: my-vault + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + azure: + container: demo-vault + accountName: vaultstorageac + accountKeySecret: azure-ac-key + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + azureKeyVault: + vaultBaseURL: https://vault-key-store.vault.azure.net/ + tenantID: aaaaaaa-bbbb-ccc-dddd-eeeeeeeee + aadClientSecret: azure-ad-client-secret + +$ kubectl apply -f docs/examples/guides/provider/aks/my-vault.yaml +vaultserver.kubevault.com/my-vault created +``` + +Check the `my-vault` status. It may take some time to reach `Running` stage. + +```bash +$ kubectl get vaultserver/my-vault -n demo +NAME NODES VERSION STATUS AGE +my-vault 1 1.2.0 Running 2m +``` + +`status` field in `my-vault` will show more detail information. + +```bash +$ kubectl get vaultserver/my-vault -n demo -o json | jq '.status' +{ + "clientPort": 8200, + "initialized": true, + "observedGeneration": "2$6206030548680361215", + "phase": "Running", + "serviceName": "my-vault", + "updatedNodes": [ + "my-vault-684c485f7-7t6zs" + ], + "vaultStatus": { + "active": "my-vault-684c485f7-7t6zs", + "unsealed": [ + "my-vault-684c485f7-7t6zs" + ] + } +} + +``` + +KubeVault operator will create a service `{metadata.name}` for `my-vault` in the same namespace. For this case, service name is `my-vault`. You can specify service configuration in [spec.serviceTemplate](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver#specservicetemplate). KubeVault operator will use that configuration to create service. + +```bash +$ kubectl get services -n demo +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +my-vault ClusterIP 10.3.244.122 8200/TCP,8201/TCP,9102/TCP 4m +``` + +The configuration used to run Vault can be found in `{metadata.name}-vault-config` configMap. For this case, it is `my-vault-vault-config`. Confidential data are omitted in this configMap. + +```bash +$ kubectl get configmaps -n demo +NAME DATA AGE +my-vault-vault-config 1 49m + +$ kubectl get configmaps/my-vault-vault-config -n demo -o yaml +apiVersion: v1 +data: + vault.hcl: |2- + + listener "tcp" { + address = "0.0.0.0:8200" + cluster_address = "0.0.0.0:8201" + tls_cert_file = "/etc/vault/tls/tls.crt" + tls_key_file = "/etc/vault/tls/tls.key" + } + + storage "azure" { + accountName = "vaultstorageac" + container = "demo-vault" + } + + telemetry { + statsd_address = "0.0.0.0:9125" + } + +kind: ConfigMap +metadata: + name: my-vault-vault-config + namespace: demo +``` + +In this `my-vault`, KubeVault operator will use self-signed certificates for Vault and also will create `{metadata.name}-vault-tls` secret containing certificates. You can optionally specify certificates in [spec.tls](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver#spectls). + +```bash +$ kubectl get secrets -n demo +NAME TYPE DATA AGE +my-vault-vault-tls Opaque 3 1h +``` + +We can see unseal keys and root token in `vault-key-store` key vault. + +![unseal keys](/docs/v2025.11.21/images/guides/provider/aks/unseal-keys.png) + +### Using Vault + +Collect the root token from `vault-key-store`: + +![root token](/docs/v2025.11.21/images/guides/provider/aks/root-token.png) + + +```bash +$ echo "cy40QTR3anQwSmt6N0p1QmlpMDM4QnprbkM=" | base64 -d +s.4A4wjt0Jkz7JuBii038BzknC +``` + +> Note: Make sure you have the permission to do above operation. Also we highly recommend not to use root token for using vault. + +For testing purpose, we are going to port forward the active vault pod, since the service we exposed for Vault is ClusterIP type. Make sure Vault cli is installed. + +```bash +$ kubectl port-forward my-vault-684c485f7-7t6zs -n demo 8200:8200 +Forwarding from 127.0.0.1:8200 -> 8200 + +# run following commands on another terminal + + +$ export VAULT_SKIP_VERIFY="true" + +$ export VAULT_ADDR='https://127.0.0.1:8200' + +$ vault status +Key Value +--- ----- +Seal Type shamir +Sealed false +Total Shares 4 +Threshold 2 +Version 1.2.0 +Cluster Name vault-cluster-0650d1f5 +Cluster ID 8a8ebf6a-a06a-0e79-cc74-a66d0d52df85 +HA Enabled false + +``` + +Set Vault token for further use. In this case, we are going to use root token(not recommended). + +```bash +$ $ export VAULT_TOKEN='s.4A4wjt0Jkz7JuBii038BzknC' + +$ vault secrets list +Path Type Accessor Description +---- ---- -------- ----------- +cubbyhole/ cubbyhole cubbyhole_9ce16bb9 per-token private secret storage +identity/ identity identity_45904875 identity store +secret/ kv kv_22970276 key/value secret storage +sys/ system system_51cd4d05 system endpoints used for control, policy and debugging + +``` + +We are going to write,read and delete a secret in Vault + +```bash +$ vault kv put secret/foo A=B +Success! Data written to: secret/foo + +# see written secret data +$ vault kv get secret/foo +== Data == +Key Value +--- ----- +A B + +# delete the secret +$ vault kv delete secret/foo +Success! Data deleted (if it existed) at: secret/foo + +# check the secret whether it is exist or not +$ vault kv get secret/foo +No value found at secret/foo +``` diff --git a/content/docs/v2025.11.21/guides/platforms/eks.md b/content/docs/v2025.11.21/guides/platforms/eks.md new file mode 100644 index 000000000..1b7247fa6 --- /dev/null +++ b/content/docs/v2025.11.21/guides/platforms/eks.md @@ -0,0 +1,390 @@ +--- +title: Deploy Vault on Amazon EKS +menu: + docs_v2025.11.21: + identifier: eks-platform + name: EKS + parent: platform-guides + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Deploy Vault on Amazon EKS + +Here, we are going to deploy Vault in Amazon EKS using KubeVault operator. We are going to use [AWS S3 bucket](https://aws.amazon.com/s3/) as Vault backend and `awsKmsSsm` unsealer mode for automatically unsealing the Vault. + +## Before You Begin + +At first, you need to have an EKS cluster. If you don't already have a cluster, create one from [here](https://aws.amazon.com/eks/). You can use [eksctl](https://github.com/weaveworks/eksctl) command line tool to create EKS cluster easily. + +- Install KubeVault operator in your cluster following the steps [here](/docs/v2025.11.21/setup/README). + +- You should be familiar with the following CRD: + - [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) + - [Unsealer](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/overview) + - [awsKmsSsm](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/aws_kms_ssm) + +- You will need a [AWS S3 Bucket](https://aws.amazon.com/s3/) to use it as Vault backend storage. In this tutorial, we are going to use `demo-vault-3` S3 bucket. + +- You will need a [AWS KMS key](https://aws.amazon.com/kms/) to use it for Vault unsealer. In this tutorial, we are going to use `218daa5f-7173-429e-a030-288b30761f79` as KMS key id. + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +### Provision Cluster + +We are going to use [eksctl](https://github.com/weaveworks/eksctl) to provision a cluster. + +```bash +$ eksctl create cluster --name demo-cluster --nodes 1 --region us-east-1 --version 1.11 +``` + +![aws ec2 instance](/docs/v2025.11.21/images/guides/provider/eks/aws-instance.png) + +### Install KubeVault operator + +See [here](/docs/v2025.11.21/setup/README). + +```bash +$ kubectl get pods -n kube-system +NAME READY STATUS RESTARTS AGE +vault-operator-798b75d78-qw74f 1/1 Running 1 2h +``` + +### Deploy Vault + +We will deploy `my-vault` on `demo` namespace. We will configure it for S3 backend. We will use `awsKmsSsm` for auto initializing and unsealing. We already created a S3 bucket `demo-vault-3` in `us-east-1` region. + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: my-vault + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + s3: + bucket: "demo-vault-3" + region: "us-east-1" + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + awsKmsSsm: + region: "us-east-1" + kmsKeyID: "218daa5f-7173-429e-a030-288b30761f79" + ssmKeyPrefix: "/cluster/demo" +``` + +Here, `spec.version` specifies the name of the [VaultServerVersion](/docs/v2025.11.21/concepts/vault-server-crds/vaultserverversion) CRD. If that does not exist, then create one. + +```bash +$ kubectl get vaultserverversions +NAME VERSION VAULT_IMAGE DEPRECATED AGE +0.11.1 0.11.1 vault:0.11.1 false 12m + +$ kubectl get vaultserverversions/0.11.1 -o yaml +apiVersion: catalog.kubevault.com/v1alpha1 +kind: VaultServerVersion +metadata: + labels: + app: vault-operator + name: 0.11.1 +spec: + deprecated: false + exporter: + image: kubevault/vault-exporter:canary + unsealer: + image: kubevault/vault-unsealer:0.2.0 + vault: + image: vault:0.11.1 + version: 0.11.1 +``` + +Now, we are going to create `my-vault` + +```bash +$ cat examples/guides/provider/eks/my-vault.yaml + apiVersion: kubevault.com/v1alpha1 + kind: VaultServer + metadata: + name: my-vault + namespace: demo + spec: + replicas: 1 + version: "1.2.0" + backend: + s3: + bucket: "demo-vault-3" + region: "us-east-1" + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + awsKmsSsm: + region: "us-east-1" + kmsKeyID: "218daa5f-7173-429e-a030-288b30761f79" + ssmKeyPrefix: "/cluster/demo" + +$ kubectl apply -f docs/examples/guides/provider/eks/my-vault.yaml +vaultserver.kubevault.com/my-vault created +``` + +> **Note**: Here, vault will attempt to retrieve credentials from the AWS metadata service. Please, make sure that it's has permission for s3 bucket, encryption key and amazon ssm. Also, you can specify dedicated credential for this using `s3.credentialSecret` and `awsKmsSsm.credentialSecret`. AWS policy are given at bottom of this tutorial. + +Check the `my-vault` status. It may take some time to reach `Running` stage. + +```bash +$ kubectl get vaultserver/my-vault -n demo +NAME NODES VERSION STATUS AGE +my-vault 1 0.11.1 Running 3m +``` + +`status` field in `my-vault` will show more detail information. + +```bash +$ kubectl get vaultserver/my-vault -n demo -o json | jq '.status' +{ + "initialized": true, + "observedGeneration": "1$6208915667192219204", + "phase": "Running", + "updatedNodes": [ + "my-vault-6f48b4d96f-mzvgm" + ], + "vaultStatus": { + "active": "my-vault-6f48b4d96f-mzvgm", + "unsealed": [ + "my-vault-6f48b4d96f-mzvgm" + ] + } +} + +``` + +KubeVault operator will create a service `{metadata.name}` for `my-vault` in the same namespace. For this case, service name is `my-vault`. You can specify service configuration in [spec.serviceTemplate](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver#specservicetemplate). KubeVault operator will use that configuration to create service. + +```bash +$ kubectl get services -n demo +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +my-vault ClusterIP 10.100.237.152 8200/TCP,8201/TCP,9102/TCP 46m +``` + +The configuration used to run Vault can be found in `{metadata.name}-vault-config` configMap. For this case, it is `my-vault-vault-config`. Confidential data are omitted in this configMap. + +```bash +$ kubectl get configmaps -n demo +NAME DATA AGE +my-vault-vault-config 1 49m + +$ kubectl get configmaps/my-vault-vault-config -n demo -o yaml +apiVersion: v1 +data: + vault.hcl: |2- + + listener "tcp" { + address = "0.0.0.0:8200" + cluster_address = "0.0.0.0:8201" + tls_cert_file = "/etc/vault/tls/server.crt" + tls_key_file = "/etc/vault/tls/server.key" + } + + storage "s3" { + bucket = "demo-vault-3" + region = "us-east-1" + } + + telemetry { + statsd_address = "0.0.0.0:9125" + } +kind: ConfigMap +metadata: + creationTimestamp: 2018-12-22T04:30:07Z + labels: + app: vault + vault_cluster: my-vault + name: my-vault-vault-config + namespace: demo + +``` + +In this `my-vault`, KubeVault operator will use self-signed certificates for Vault and also will create `{metadata.name}-vault-tls` secret containing certificates. You can optionally specify certificates in [spec.tls](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver#spectls). + +```bash +$ kubectl get secrets -n demo +NAME TYPE DATA AGE +my-vault-vault-tls Opaque 3 1h +``` + +We can see unseal keys and root token in AWS System Manager Parameter Store in the `unsealer.region` region. For this case, in `us-east-1` region. + +![unseal keys](/docs/v2025.11.21/images/guides/provider/eks/unseal-keys.png) + +### Using Vault + +Download and decrypt the root token: +```bash +$ aws ssm get-parameter --name vault-root-token --region us-east-1 --output json | jq -r '.Parameter.Value' | base64 -d - > root.enc + +$ tree . +. +└── root.enc + +$ aws kms decrypt --ciphertext-blob fileb://root.enc --output text --query Plaintext --encryption-context "Tool=vault-unsealer" --region us-east-1 | base64 -d - +9116f849-2085-9c28-015f-aec3e184e90f +``` + +> Note: Make sure you have the permission to do above operation. Also we highly recommend not to use root token for using vault. + +For testing purpose, we are going to port forward the active vault pod, since the service we exposed for Vault is ClusterIP type. Make sure Vault cli is installed. + +```bash +$ kubectl port-forward my-vault-6f48b4d96f-mzvgm -n demo 8200:8200 +Forwarding from 127.0.0.1:8200 -> 8200 + +# run following commands on another terminal +$ export VAULT_SKIP_VERIFY="true" + +$ export VAULT_ADDR='https://127.0.0.1:8200' + +$ vault status +Key Value +--- ----- +Seal Type shamir +Sealed false +Total Shares 4 +Threshold 2 +Version 0.11.1 +Cluster Name vault-cluster-e4eda2ce +Cluster ID d05fec0c-7e09-20f6-0d88-0283ed9c7b72 +HA Enabled false + +``` + +Set Vault token for further use. In this case, we are going to use root token(not recommended). + +```bash +$ export VAULT_TOKEN='9116f849-2085-9c28-015f-aec3e184e90f' + +$ vault secrets list +Path Type Accessor Description +---- ---- -------- ----------- +cubbyhole/ cubbyhole cubbyhole_9ce16bb9 per-token private secret storage +identity/ identity identity_45904875 identity store +secret/ kv kv_22970276 key/value secret storage +sys/ system system_51cd4d05 system endpoints used for control, policy and debugging + +``` + +We are going to write,read and delete a secret in Vault + +```bash +$ vault kv put secret/foo A=B +Success! Data written to: secret/foo + +# see written secret data +$ vault kv get secret/foo +== Data == +Key Value +--- ----- +A B + +# delete the secret +$ vault kv delete secret/foo +Success! Data deleted (if it existed) at: secret/foo + +# check the secret whether it is exist or not +$ vault kv get secret/foo +No value found at secret/foo + +``` + +## AWS IAM Policy + +Policy for S3 bucket access: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "VaultListBuckets", + "Effect": "Allow", + "Action": [ + "s3:ListAllMyBuckets", + "s3:HeadBucket" + ], + "Resource": "*" + }, + { + "Sid": "VaultAccessBuckets", + "Effect": "Allow", + "Action": "s3:*", + "Resource": [ + "arn:aws:s3:::", + "arn:aws:s3:::/*" + ] + } + ] +} +``` + +Policy for KMS: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "VaultUnsealerEncryptDecryptKms", + "Effect": "Allow", + "Action": [ + "kms:Decrypt", + "kms:Encrypt", + "kms:DescribeKey" + ], + "Resource": "arn:aws:kms:::key/" + }, + { + "Sid": "VaultUnsealerGetKMS", + "Effect": "Allow", + "Action": "kms:ListKeys", + "Resource": "*" + } + ] +} +``` + +Policy for SSM: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "VaultUnsealerParametersAccess", + "Effect": "Allow", + "Action": [ + "ssm:PutParameter", + "ssm:DeleteParameter", + "ssm:GetParameters" + ], + "Resource": "arn:aws:ssm:*:*:parameter/*" + } + ] +} +``` diff --git a/content/docs/v2025.11.21/guides/platforms/external-vault.md b/content/docs/v2025.11.21/guides/platforms/external-vault.md new file mode 100644 index 000000000..7211cf72f --- /dev/null +++ b/content/docs/v2025.11.21/guides/platforms/external-vault.md @@ -0,0 +1,214 @@ +--- +title: Manage External Vault using KubeVault operator +menu: + docs_v2025.11.21: + identifier: external-vault-platform + name: External Vault + parent: platform-guides + weight: 25 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Manage External Vault using KubeVault operator + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. These Vault servers can be running outside a Kubernetes cluster or running inside a Kubernetes cluster but provisioned using a Helm chart. + +The KubeVault operator can perform the following operations for externally provisioned Vault servers: + +- Manage Vault [policy](https://www.vaultproject.io/docs/concepts/policies.html) using [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) and [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding). Guides can be found [here](/docs/v2025.11.21/guides/policy-management/overview). + +- Manage [AWS secret engine](https://www.vaultproject.io/docs/secrets/aws/index.html#aws-secrets-engine) using [AWSRole](/docs/v2025.11.21/concepts/secret-engine-crds/aws-secret-engine/awsrole) and [SecretAccessRequest](/docs/v2025.11.21/concepts/secret-engine-crds/secret-access-request). Guides can be found [here](/docs/v2025.11.21/guides/secret-engines/aws/overview). + +- Manage [PostgreSQL Database secret engine](https://www.vaultproject.io/api/secret/databases/postgresql.html) using [PostgresRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/postgresrole) and [SecretAccessRequest](/docs/v2025.11.21/concepts/secret-engine-crds/secret-access-request). Guides can be found [here](/docs/v2025.11.21/guides/secret-engines/postgres/overview). + +- Manage [MongoDB Database secret engine](https://www.vaultproject.io/api/secret/databases/mongodb.html) using [MongoDBRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mongodb) and [SecretAccessRequest](/docs/v2025.11.21/concepts/secret-engine-crds/secret-access-request). Guides can be found [here](/docs/v2025.11.21/guides/secret-engines/mongodb/overview). + +In this tutorial, we are going to show how we can use KubeVault operator for Vault which is not provisioned by KubeVault operator. + +## Connecting with Vault + +We have a Vault running which can be accessible by the address `http://vault.default.svc:8200` from Kubernetes cluster. KubeVault operator use [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) to communicate with Vault. [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) provides a way of specifying Vault connection information and credential. Following authentication methods are currently supported by KubeVault operator using AppBinding: + +- [Token Auth Method](https://www.vaultproject.io/docs/auth/token.html#token-auth-method) +- [Kubernetes Auth Method](https://www.vaultproject.io/docs/auth/kubernetes.html) +- [AWS IAM Auth Method](https://www.vaultproject.io/docs/auth/aws.html#iam-auth-method) +- [Userpass Auth Method](https://www.vaultproject.io/docs/auth/userpass.html) +- [TLS Certificates Auth Method](https://www.vaultproject.io/docs/auth/cert.html) + +Vault authentication using AppBinding can be found in [here](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/overview). + +In this tutorial, we are going to use [Kubernetes Auth Method](https://www.vaultproject.io/docs/auth/kubernetes.html). + +Now, we are going to enable and configure [Kubenetes auth](https://www.vaultproject.io/docs/auth/kubernetes.html) in Vault. + +- Create a service account and cluster role bindings that allow that service account to authenticate with the review token API. + + ```bash + $ cat docs/examples/guides/provider/external-vault/token-reviewer-sa.yaml + apiVersion: v1 + kind: ServiceAccount + metadata: + name: token-reviewer + namespace: demo + + $ cat docs/examples/guides/provider/external-vault/token-review-binding.yaml + apiVersion: rbac.authorization.k8s.io/v1beta1 + kind: ClusterRoleBinding + metadata: + name: role-tokenreview-binding + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator + subjects: + - kind: ServiceAccount + name: token-reviewer + namespace: demo + + $ kubectl apply -f docs/examples/guides/provider/external-vault/token-reviewer-sa.yaml + serviceaccount/token-reviewer created + + $ kubectl apply -f docs/examples/guides/provider/external-vault/token-review-binding.yaml + clusterrolebinding.rbac.authorization.k8s.io/role-tokenreview-binding created + ``` + +- Enable Kubernetes auth in Vault. + + ```bash + $ vault auth enable kubernetes + Success! Enabled Kubernetes auth method at: kubernetes/ + ``` + +- Configure Kubernetes auth in Vault. + + ```bash + $ kubectl get sa token-reviewer -n demo -o jsonpath="{.secrets[*]['name']}" + token-reviewer-token-fvqsv + + $ export SA_JWT_TOKEN=$(kubectl get secret token-reviewer-token-fvqsv -n demo -o jsonpath="{.data.token}" | base64 --decode; echo) + + $ export SA_CA_CRT=$(kubectl get secret token-reviewer-token-fvqsv -n demo -o jsonpath="{.data['ca\.crt']}" | base64 --decode; echo) + + $ vault write auth/kubernetes/config \ + token_reviewer_jwt="$SA_JWT_TOKEN" \ + kubernetes_host="https://192.168.99.100:8443" \ + kubernetes_ca_cert="$SA_CA_CRT" + Success! Data written to: auth/kubernetes/config + ``` + +We are going to create a Vault [policy](https://www.vaultproject.io/docs/concepts/policies.html). It has permission to manage policy and Kubernetes role in Vault. + +```bash +$ cat docs/examples/guides/provider/external-vault/policy-admin.hcl +path "sys/policy/*" { + capabilities = ["create", "update", "read", "delete", "list"] +} + +path "sys/policy" { + capabilities = ["read", "list"] +} + +path "auth/kubernetes/role" { + capabilities = ["read", "list"] +} + +path "auth/kubernetes/role/*" { + capabilities = ["create", "update", "read", "delete", "list"] +} + +$ vault policy write policy-admin docs/examples/guides/provider/external-vault/policy-admin.hcl +Success! Uploaded policy: policy-admin +``` + +We are going to assign the above policy to a service account `policy-admin` so that we can use that service account to manage policy and Kubernetes role. + +```bash +$ cat docs/examples/guides/provider/external-vault/policy-admin-sa.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: policy-admin + namespace: demo + +$ kubectl apply -f docs/examples/guides/provider/external-vault/policy-admin-sa.yaml +serviceaccount/policy-admin created + +$ vault write auth/kubernetes/role/policy-admin-role \ + bound_service_account_names=policy-admin \ + bound_service_account_namespaces=demo \ + policies=policy-admin \ + ttl=24h +Success! Data written to: auth/kubernetes/role/policy-admin-role +``` + +Now, we are going create AppBinding that will contain Vault information. For authentication, service account `policy-admin` and Kubernetes role `policy-admin-role` will be used. + +```bash +$ cat docs/examples/guides/provider/external-vault/vault-app.yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + clientConfig: + url: http://vault.default.svc:8200 + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9ERXlNamN3TkRVNU1qVmFGdzB5T0RFeU1qUXdORFU1TWpWYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMVhid2wyQ1NNc2VQTU5RRzhMd3dUVWVOCkI1T05oSTlDNzFtdUoyZEZjTTlUc1VDQnlRRk1weUc5dWFvV3J1ZDhtSWpwMVl3MmVIUW5udmoybXRmWGcrWFcKSThCYkJUaUFKMWxMMFE5MlV0a1BLczlXWEt6dTN0SjJUR1hRRDhhbHZhZ0JrR1ViOFJYaUNqK2pnc1p6TDRvQQpNRWszSU9jS0xnMm9ldFZNQ0hwNktpWTBnQkZiUWdJZ1A1TnFwbksrbU02ZTc1ZW5hWEdBK2V1d09FT0YwV0Z2CmxGQmgzSEY5QlBGdTJKbkZQUlpHVDJKajBRR1FNeUxodEY5Tk1pZTdkQnhiTWhRVitvUXp2d1EvaXk1Q2pndXQKeDc3d29HQ2JtM0o4cXRybUg2Tjl6Tlc3WlR0YTdLd05PTmFoSUFEMSsrQm5rc3JvYi9BYWRKT0tMN2dLYndJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFXeWFsdUt3Wk1COWtZOEU5WkdJcHJkZFQyZnFTd0lEOUQzVjN5anBlaDVCOUZHN1UKSS8wNmpuRVcyaWpESXNHNkFDZzJKOXdyaSttZ2VIa2Y2WFFNWjFwZHRWeDZLVWplWTVnZStzcGdCRTEyR2NPdwpxMUhJb0NrekVBMk5HOGRNRGM4dkQ5WHBQWGwxdW5veWN4Y0VMeFVRSC9PRlc4eHJxNU9vcXVYUkxMMnlKcXNGCmlvM2lJV3EvU09Yajc4MVp6MW5BV1JSNCtSYW1KWjlOcUNjb1Z3b3R6VzI1UWJKWWJ3QzJOSkNENEFwOUtXUjUKU2w2blk3NVMybEdSRENsQkNnN2VRdzcwU25seW5mb3RaTUpKdmFzbStrOWR3U0xtSDh2RDNMMGNGOW5SOENTSgpiTjBiZzczeVlWRHgyY3JRYk0zcko4dUJnY3BsWlRpUy91SXJ2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: kubernetes + vaultRole: policy-admin-role + kubernetes: + serviceAccountName: policy-admin + +$ kubectl apply -f docs/examples/guides/provider/external-vault/vault-app.yaml +appbinding.appcatalog.appscode.com/vault-app created +``` + +If KubeVault operator uses the above AppBinding `vault-app`, then it will have the permission that is given to service account `policy-admin` by `policy-admin-role` role. Now, we are going to create [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) using `vault-app` AppBinding. + +```bash +$ cat docs/examples/guides/provider/external-vault/demo-policy.yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: demo-policy + namespace: demo +spec: + ref: + name: vault-app + namespace: demo + policyDocument: | + path "secret/*" { + capabilities = ["create", "read", "update", "delete", "list"] + } + +$ kubectl apply -f docs/examples/guides/provider/external-vault/demo-policy.yaml +vaultpolicy.policy.kubevault.com/demo-policy created + +$ kubectl get vaultpolicies -n demo +NAME STATUS AGE +demo-policy Success 3s + +# To resolve the naming conflict, name of policy in Vault will follow this format: 'k8s.{clusterName}.{metadata.namespace}.{metadata.name}'. For this case, it is 'k8s.-.demo.demo-policy'. +$ vault policy list +default +k8s.-.demo.demo-policy +policy-admin +root + +$ vault policy read k8s.-.demo.demo-policy +path "secret/*" { + capabilities = ["create", "read", "update", "delete", "list"] +} +``` diff --git a/content/docs/v2025.11.21/guides/platforms/gke.md b/content/docs/v2025.11.21/guides/platforms/gke.md new file mode 100644 index 000000000..f5d9a3ddc --- /dev/null +++ b/content/docs/v2025.11.21/guides/platforms/gke.md @@ -0,0 +1,373 @@ +--- +title: Deploy Vault on Google Kubernetes Engine (GKE) +menu: + docs_v2025.11.21: + identifier: gke-platform + name: GKE + parent: platform-guides + weight: 20 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Deploy Vault on Google Kubernetes Engine (GKE) + +Here, we are going to deploy Vault in GKE using KubeVault operator. We are going to use [GCS bucket](https://cloud.google.com/storage/docs/) as Vault backend and `googleKmsGcs` unsealer mode for automatically unsealing the Vault. + +## Before You Begin + +At first, you need to have a GKE cluster. If you don't already have a cluster, create one from [here](https://cloud.google.com/kubernetes-engine/). + +- Install KubeVault operator in your cluster following the steps [here](/docs/v2025.11.21/setup/README). + +- You should be familiar with the following CRD: + - [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) + - [Unsealer](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/overview) + - [googleKmsGcs](/docs/v2025.11.21/concepts/vault-server-crds/unsealer/google_kms_gcs) + +- You will need a [GCS bucket](https://cloud.google.com/storage/docs/) to use it as Vault backend storage. In this tutorial, we are going to use `demo-vault` GCS bucket. + +- You will need a [Google KMS](https://cloud.google.com/kms/) crypto key to use it for Vault unsealer. In this tutorial, we are going to use key `vault-key` int `vault` key ring. + + +### Provision Cluster + +We are going to use [gcloud](https://cloud.google.com/sdk/gcloud/) to provision a cluster. + +```bash +$ gcloud container clusters create vault \ + --enable-autorepair \ + --cluster-version 1.11.4-gke.13 \ + --machine-type n1-standard-2 \ + --num-nodes 1 \ + --zone us-east1-b \ + --project ackube +``` + +![gke instance](/docs/v2025.11.21/images/guides/provider/gke/gke-cluster.png) + +Now, we are going to create service account and set access permission to this service account. + +```bash +$ gcloud iam service-accounts create vault-sa \ + --display-name "vault service account" \ + --project ackube +Created service account [vault-sa]. +``` + +Grant access to bucket: + +```bash +$ gsutil iam ch \ + serviceAccount:vault-sa@ackube.iam.gserviceaccount.com:objectAdmin \ + gs://demo-vault +``` + +```bash +$ gsutil iam ch \ + serviceAccount:vault-sa@ackube.iam.gserviceaccount.com:legacyBucketReader \ + gs://demo-vault +``` + +Grant access to the crypto key: + +```bash +$ gcloud kms keys add-iam-policy-binding \ + vault-key \ + --location global \ + --keyring vault \ + --member serviceAccount:vault-sa@ackube.iam.gserviceaccount.com \ + --role roles/cloudkms.cryptoKeyEncrypterDecrypter \ + --project ackube +``` + +### Install KubeVault operator + +See [here](/docs/v2025.11.21/setup/README). + +```bash +$ kubectl get pods -n kube-system +NAME READY STATUS RESTARTS AGE +vault-operator-7cc8cdf7f6-jmhg4 1/1 Running 6 8m +``` + +### Deploy Vault + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +We will deploy `my-vault` on `demo` namespace. We will configure it for GCS backend. We will use `googleKmsGcs` for auto initializing and unsealing. We already created a GCS bucket `demo-vault`. + +```yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: my-vault + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + gcs: + bucket: "demo-vault" + credentialSecret: "google-cred" + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + googleKmsGcs: + bucket: "demo-vault" + kmsProject: "ackube" + kmsLocation: "global" + kmsKeyRing: "vault" + kmsCryptoKey: "vault-key" + credentialSecret: "google-cred" +``` + +Here, `spec.version` specifies the name of the [VaultServerVersion](/docs/v2025.11.21/concepts/vault-server-crds/vaultserverversion) CRD. If that does not exist, then create one. + +```bash +$ kubectl get vaultserverversions +NAME VERSION VAULT_IMAGE DEPRECATED AGE +1.2.0 1.2.0 vault:1.2.0 false 1m + +$ kubectl get vaultserverversions/1.2.0 -o yaml +apiVersion: catalog.kubevault.com/v1alpha1 +kind: VaultServerVersion +metadata: + name: 1.2.0 +spec: + version: 1.2.0 + deprecated: false + vault: + image: vault:1.2.0 + unsealer: + image: kubevault/vault-unsealer:v0.3.0 + exporter: + image: kubevault/vault-exporter:0.1.0 +``` + +`spec.backend.gcs.credentialSecret` and `spec.unsealer.mode.googleKmsGcs.credentialSecret` specifies the name of the Kubernetes secret containing `vault-sa@ackube.iam.gserviceaccount.com` credential. + +```bash +$ kubectl get secrets/google-cred -n demo -o yaml +apiVersion: v1 +data: + sa.json: ewogICJ0eXBlIjogIn... +kind: Secret +metadata: + name: google-cred + namespace: demo +type: Opaque + +``` + +Now, we are going to create `my-vault` in `demo` namespace. + +```bash +$ cat examples/guides/provider/gke/my-vault.yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: my-vault + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + gcs: + bucket: "demo-vault" + credentialSecret: "google-cred" + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + googleKmsGcs: + bucket: "demo-vault" + kmsProject: "ackube" + kmsLocation: "global" + kmsKeyRing: "vault" + kmsCryptoKey: "vault-key" + credentialSecret: "google-cred" + +$ kubectl apply -f docs/examples/guides/provider/gke/my-vault.yaml +vaultserver.kubevault.com/my-vault created +``` + +Check the `my-vault` status. It may take some time to reach `Running` stage. + +```bash +$ kubectl get vaultserver/my-vault -n demo +NAME NODES VERSION STATUS AGE +my-vault 1 1.2.0 Running 2m +``` + +`status` field in `my-vault` will show more detail information. + +```bash +$ kubectl get vaultserver/my-vault -n demo -o json | jq '.status' +{ + "clientPort": 8200, + "initialized": true, + "observedGeneration": "1$6208915667192219204", + "phase": "Running", + "serviceName": "my-vault", + "updatedNodes": [ + "my-vault-75b6f87dbb-kq4tp" + ], + "vaultStatus": { + "active": "my-vault-75b6f87dbb-kq4tp", + "unsealed": [ + "my-vault-75b6f87dbb-kq4tp" + ] + } +} + +``` + +KubeVault operator will create a service `{metadata.name}` for `my-vault` in the same namespace. For this case, service name is `my-vault`. You can specify service configuration in [spec.serviceTemplate](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver#specservicetemplate). KubeVault operator will use that configuration to create service. + +```bash +$ kubectl get services -n demo +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +my-vault ClusterIP 10.3.244.122 8200/TCP,8201/TCP,9102/TCP 4m +``` + +The configuration used to run Vault can be found in `{metadata.name}-vault-config` configMap. For this case, it is `my-vault-vault-config`. Confidential data are omitted in this configMap. + +```bash +$ kubectl get configmaps -n demo +NAME DATA AGE +my-vault-vault-config 1 49m + +$ kubectl get configmaps/my-vault-vault-config -n demo -o yaml +apiVersion: v1 +data: + vault.hcl: |2- + + listener "tcp" { + address = "0.0.0.0:8200" + cluster_address = "0.0.0.0:8201" + tls_cert_file = "/etc/vault/tls/server.crt" + tls_key_file = "/etc/vault/tls/server.key" + } + + storage "gcs" { + bucket = "demo-vault" + } + + telemetry { + statsd_address = "0.0.0.0:9125" + } +kind: ConfigMap +metadata: + name: my-vault-vault-config + namespace: demo +``` + +In this `my-vault`, KubeVault operator will use self-signed certificates for Vault and also will create `{metadata.name}-vault-tls` secret containing certificates. You can optionally specify certificates in [spec.tls](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver#spectls). + +```bash +$ kubectl get secrets -n demo +NAME TYPE DATA AGE +my-vault-vault-tls Opaque 3 1h +``` + +We can see unseal keys and root token in `demo-vault` bucket. + +![unseal keys](/docs/v2025.11.21/images/guides/provider/gke/gke-unseal-keys.png) + +### Using Vault + +Download and decrypt the root token: + +```bash +$ export VAULT_TOKEN=$(gsutil cat gs://demo-vault/vault-root-token | \ + gcloud kms decrypt \ + --project ackube \ + --location global \ + --keyring vault \ + --key vault-key \ + --ciphertext-file - \ + --plaintext-file - ) + +$ echo $VAULT_TOKEN +s.5DEELd1OiRmwfnrqfqQeguug +``` + +> Note: Make sure you have the permission to do above operation. Also we highly recommend not to use root token for using vault. + +For testing purpose, we are going to port forward the active vault pod, since the service we exposed for Vault is ClusterIP type. Make sure Vault cli is installed. + +```bash +$ kubectl port-forward my-vault-75b6f87dbb-kq4tp -n demo 8200:8200 +Forwarding from 127.0.0.1:8200 -> 8200 + +# run following commands on another terminal +$ export VAULT_SKIP_VERIFY="true" + +$ export VAULT_ADDR='https://127.0.0.1:8200' + +$ vault status +Key Value +--- ----- +Seal Type shamir +Sealed false +Total Shares 4 +Threshold 2 +Version 1.2.0 +Cluster Name vault-cluster-84d6b1b0 +Cluster ID bb6487bb-0deb-9e95-144e-e85c9ebd07eb +HA Enabled false + +``` + +Set Vault token for further use. In this case, we are going to use root token(not recommended). + +```bash +$ export VAULT_TOKEN='s.5DEELd1OiRmwfnrqfqQeguug' + +$ vault secrets list +Path Type Accessor Description +---- ---- -------- ----------- +cubbyhole/ cubbyhole cubbyhole_9ce16bb9 per-token private secret storage +identity/ identity identity_45904875 identity store +secret/ kv kv_22970276 key/value secret storage +sys/ system system_51cd4d05 system endpoints used for control, policy and debugging + +``` + +We are going to write,read and delete a secret in Vault + +```bash +$ vault kv put secret/foo A=B +Success! Data written to: secret/foo + +# see written secret data +$ vault kv get secret/foo +== Data == +Key Value +--- ----- +A B + +# delete the secret +$ vault kv delete secret/foo +Success! Data deleted (if it existed) at: secret/foo + +# check the secret whether it is exist or not +$ vault kv get secret/foo +No value found at secret/foo + +``` diff --git a/content/docs/v2025.11.21/guides/platforms/multi-cluster-vault.md b/content/docs/v2025.11.21/guides/platforms/multi-cluster-vault.md new file mode 100644 index 000000000..21ae06a3c --- /dev/null +++ b/content/docs/v2025.11.21/guides/platforms/multi-cluster-vault.md @@ -0,0 +1,224 @@ +--- +title: Use a Vault Server with Multiple Kubernetes Clusters +menu: + docs_v2025.11.21: + identifier: multi-cluster-platform + name: Multi-Cluster + parent: platform-guides + weight: 100 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Use a Vault Server with Multiple Kubernetes Clusters + +In this tutorial, we are going to show how to use KubeVault operators in multiple Kubernetes clusters against a shared Vault server. + +To being with, we have created two GKE clusters. + +![cluster image](/docs/v2025.11.21/images/guides/provider/multi-cluster/gke-cluster.png) + +We are going to install KubeVault operator in `demo-cluster-1` using Helm 3. We are going to set `--cluster-name` flag. This flag value will be used by KubeVault operator when creating resources in Vault. + +```bash +$ kubectl config current-context +gke_ackube_us-central1-a_demo-cluster-1 + +$ helm install kubevault oci://ghcr.io/appscode-charts/kubevault \ + --version {{< param "info.version" >}} \ + --namespace kubevault --create-namespace \ + --set clusterName=demo-cluster-1 + +$ kubectl get pods -n kube-system +NAME READY STATUS RESTARTS AGE +vault-operator-5fc7666575-8v6ft 1/1 Running 0 1h +``` + +We are going to deploy Vault in `demo-cluster-1` using KubeVault operator. Guides to deploy Vault in GKE can be found [here](/docs/v2025.11.21/guides/platforms/gke). + +```bash +$ kubectl get vaultserverversions/1.2.0 -o yaml +apiVersion: catalog.kubevault.com/v1alpha1 +kind: VaultServerVersion +metadata: + name: 1.2.0 +spec: + version: 1.2.0 + deprecated: false + vault: + image: vault:1.2.0 + unsealer: + image: kubevault/vault-unsealer:v0.3.0 + exporter: + image: kubevault/vault-exporter:0.1.0 + +$ cat examples/guides/provider/multi-cluster/my-vault.yaml +cat examples/guides/provider/multi-cluster/my-vault.yaml +apiVersion: kubevault.com/v1alpha1 +kind: VaultServer +metadata: + name: my-vault + namespace: demo +spec: + replicas: 1 + version: "1.2.0" + backend: + gcs: + bucket: "demo-vault" + credentialSecret: "google-cred" + serviceTemplate: + spec: + type: LoadBalancer + loadBalancerIP: 104.155.177.205 + tls: + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9UQXhNRGN3T1RNNE1UaGFGdzB5T1RBeE1EUXdPVE00TVRoYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdXZxWFJrMGZrMHNWMFpoMDQwd0FaVTBhCkhlRW9vUnlVMlpaaGtjS3dPS201N2pUWkJaMEkvMjg2dTNpUVFpc2tMTFNjYUtvaHp0c012RXFCU0JpNU5MNEMKVXVQbm5CZklIVVo1UDhwQWNOUXJ5SURETGxXZTFBTEVKU0N0L3daRG5mMkRPdXZGSVMybFJVZDV2WFp1dlVjWgptdml5T3VUOW9CclNwNkh5YUpRYkUrZk1qQTRvZ0ZoQWZmN1djMm1DVk1jam8wU3htK2lrVWxVZWhXdWd4T3M0Cm5GUG5pWmt3a1h0KzFweU45WjltclhwUTlZM3FvdGlmdk1aUnVhVS9hbjUxOUZqSWdzVUZtRGVoZ3c3blJwYkkKZ0NGeUNPSlc5ZTNDczNRVTViVTJYUk1leDBlTDZReTZJY2dDdGZIRmpBeGhjUHAzeEJjRW5XSEdONDM2dHdJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFUMzFuQUNpMmNySW0rWCtGZUNocjJJcnhZeGFDSlpLNW92Y1Jqem5TZFR0N2JadWoKcTVZQW5jbitESDlxUURkczFVTEdjR1ZISlpiS3RORU9GVVlJbDVXYUZBVnNBMTJoaURCZnJXc24ydUV6K0pUVwovcStLSVE0OW1LUWV1TG80bkVoQnRJYjJzaXBKMmxmUEVyUXhHQllrZ3lOT05zOTN5NEdPVXU4dVdBaUFqZ21oCmM4a1QzTVV0ZVRNUHczQ3JKU2ZtbGUxQkk0bkNPNXEreW54Zk56SXZqZU5PYnNvVTdOOVhoZTdCQjZSSzQ1akgKVW41bzBTZkkrR0dYU0l5eWFxVHlJRUJkK3Nub1pMRWQzMm9DeWJFOC9QajE3T3BDZHhhd0ZnZWJGUnNEQ2pkRQo0bUI2RmVPMi9md3VFUk5lTlZnczBHMjBPc2t4cDJoTWJRYUlJZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + tlsSecret: vault-tls + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + googleKmsGcs: + bucket: "demo-vault" + kmsProject: "ackube" + kmsLocation: "global" + kmsKeyRing: "vault" + kmsCryptoKey: "vault-key" + credentialSecret: "google-cred" + +$ kubectl apply -f docs/examples/guides/provider/multi-cluster/my-vault.yaml +vaultserver.kubevault.com/my-vault created + +$ kubectl get vaultserver my-vault -n demo +NAME NODES VERSION STATUS AGE +my-vault 1 1.2.0 Running 1m + +$ kubectl get services -n demo +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +my-vault LoadBalancer 10.3.251.241 104.155.177.205 8200:31542/TCP,8201:31390/TCP,9102:30911/TCP 2m +``` + +Now we are going to create `demo-policy-secret-admin` [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) in `demo-cluster-1`. Guides to manage policy in Vault can be found [here](/docs/v2025.11.21/guides/policy-management/overview). + +```bash +$ cat examples/guides/provider/multi-cluster/demo-policy-secret-admin.yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: demo-policy-secret-admin + namespace: demo +spec: + ref: + name: my-vault + namespace: demo + policyDocument: | + path "secret/*" { + capabilities = ["create", "read", "update", "delete", "list"] + } +$ kubectl apply -f docs/examples/guides/provider/multi-cluster/demo-policy-secret-admin.yaml +vaultpolicy.policy.kubevault.com/demo-policy-secret-admin created + +$ kubectl get vaultpolicies -n demo +NAME STATUS AGE +demo-policy-secret-admin Success 1m +``` + +Check the created `demo-policy-secret-admin` [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) in Vault. To resolve the naming conflict, name of policy in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. For this case, it is `k8s.demo-cluster-1.demo.demo-policy-secret-admin`. + +```bash +$ export VAULT_ADDR='https://104.155.177.205:31542' + +$ export VAULT_CACERT="cert/ca.crt" + +$ export VAULT_TOKEN="s.KLJFDIUJLKDFDLKFJ" + +$ vault policy list +default +k8s.demo-cluster-1.demo.demo-policy-secret-admin +my-vault-policy-controller +root + +``` + +We are going to install KubeVault operator in `demo-cluster-2` using Helm 3. We are going to set `--cluster-name`, this flag value will be used by KubeVault operator when creating resource in Vault. + +```bash +$ kubectl config current-context +gke_ackube_us-central1-a_demo-cluster-2 + +$ helm install kubevault oci://ghcr.io/appscode-charts/kubevault \ + --version {{< param "info.version" >}} \ + --namespace kubevault --create-namespace \ + --set clusterName=demo-cluster-2 + +$ kubectl get pods -n kube-system +NAME READY STATUS RESTARTS AGE +vault-operator-5fc7666575-8v6ft 1/1 Running 0 1h +``` + +Now we are going to create an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and credential information of the Vault that is deployed in `demo-cluster-1`. In this AppBinding, we are going to use [token auth](https://www.vaultproject.io/docs/auth/token.html#token-auth-method). Guides to Vault authentication using AppBinding can be found [here](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/overview). + +```bash +$ cat examples/guides/provider/multi-cluster/vault-app.yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault-app + namespace: demo +spec: + secret: + name: vault-token + clientConfig: + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9UQXhNRGN3T1RNNE1UaGFGdzB5T1RBeE1EUXdPVE00TVRoYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdXZxWFJrMGZrMHNWMFpoMDQwd0FaVTBhCkhlRW9vUnlVMlpaaGtjS3dPS201N2pUWkJaMEkvMjg2dTNpUVFpc2tMTFNjYUtvaHp0c012RXFCU0JpNU5MNEMKVXVQbm5CZklIVVo1UDhwQWNOUXJ5SURETGxXZTFBTEVKU0N0L3daRG5mMkRPdXZGSVMybFJVZDV2WFp1dlVjWgptdml5T3VUOW9CclNwNkh5YUpRYkUrZk1qQTRvZ0ZoQWZmN1djMm1DVk1jam8wU3htK2lrVWxVZWhXdWd4T3M0Cm5GUG5pWmt3a1h0KzFweU45WjltclhwUTlZM3FvdGlmdk1aUnVhVS9hbjUxOUZqSWdzVUZtRGVoZ3c3blJwYkkKZ0NGeUNPSlc5ZTNDczNRVTViVTJYUk1leDBlTDZReTZJY2dDdGZIRmpBeGhjUHAzeEJjRW5XSEdONDM2dHdJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFUMzFuQUNpMmNySW0rWCtGZUNocjJJcnhZeGFDSlpLNW92Y1Jqem5TZFR0N2JadWoKcTVZQW5jbitESDlxUURkczFVTEdjR1ZISlpiS3RORU9GVVlJbDVXYUZBVnNBMTJoaURCZnJXc24ydUV6K0pUVwovcStLSVE0OW1LUWV1TG80bkVoQnRJYjJzaXBKMmxmUEVyUXhHQllrZ3lOT05zOTN5NEdPVXU4dVdBaUFqZ21oCmM4a1QzTVV0ZVRNUHczQ3JKU2ZtbGUxQkk0bkNPNXEreW54Zk56SXZqZU5PYnNvVTdOOVhoZTdCQjZSSzQ1akgKVW41bzBTZkkrR0dYU0l5eWFxVHlJRUJkK3Nub1pMRWQzMm9DeWJFOC9QajE3T3BDZHhhd0ZnZWJGUnNEQ2pkRQo0bUI2RmVPMi9md3VFUk5lTlZnczBHMjBPc2t4cDJoTWJRYUlJZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + url: https://104.155.177.205:8200 + +$ kubectl apply -f docs/examples/guides/provider/multi-cluster/vault-app.yaml +appbinding.appcatalog.appscode.com/vault-app created +``` + +Now we are going to create `demo-policy-secret-reader` [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) in `demo-cluster-2`. + +```bash +$ cat examples/guides/provider/multi-cluster/demo-policy-secret-reader.yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: demo-policy-secret-reader + namespace: demo +spec: + ref: + name: vault-app + namespace: demo + policyDocument: | + path "secret/*" { + capabilities = ["read", "list"] + } + +$ kubectl apply -f docs/examples/guides/provider/multi-cluster/demo-policy-secret-reader.yaml +vaultpolicy.policy.kubevault.com/demo-policy-secret-reader created + +$ kubectl get vaultpolicies -n demo +NAME STATUS AGE +demo-policy-secret-reader Success 1m +``` + +Check the created `demo-policy-secret-reader` [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) in Vault. To resolve the naming conflict, name of policy in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. For this case, it is `k8s.demo-cluster-2.demo.demo-policy-secret-reader`. + +```bash +$ vault policy list +default +k8s.demo-cluster-1.demo.demo-policy-secret-admin +k8s.demo-cluster-2.demo.demo-policy-secret-reader +my-vault-policy-controller +root + +``` + +This how we can use KubeVault operator in multiple Kubernetes clusters with a shared Vault Server without naming conflict. diff --git a/content/docs/v2025.11.21/guides/policy-management/_index.md b/content/docs/v2025.11.21/guides/policy-management/_index.md new file mode 100755 index 000000000..853a63c84 --- /dev/null +++ b/content/docs/v2025.11.21/guides/policy-management/_index.md @@ -0,0 +1,17 @@ +--- +title: Policy Management Guides | KubeVault +menu: + docs_v2025.11.21: + identifier: policy-management-guides + name: Policy Management + parent: guides + weight: 20 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/policy-management/overview.md b/content/docs/v2025.11.21/guides/policy-management/overview.md new file mode 100644 index 000000000..fdbad86b0 --- /dev/null +++ b/content/docs/v2025.11.21/guides/policy-management/overview.md @@ -0,0 +1,356 @@ +--- +title: Vault Policy Management +menu: + docs_v2025.11.21: + identifier: overview-policy-management + name: Overview + parent: policy-management-guides + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Vault Policy Management + +You can easily manage the Vault [policies](https://www.vaultproject.io/docs/concepts/policies.html) in Kubernetes native way using the KubeVault operator. The operator also provides functionality to create auth method roles that bind policies. + +You should be familiar with the following CRD: + +- [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) +- [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +## Before you begin + +- Install KubeVault operator in your cluster following the steps [here](/docs/v2025.11.21/setup/README). + +- Deploy the Vault server or configure an existing one. + - [Setup Vault Server](/docs/v2025.11.21/guides/vault-server/overview#setup-vault-server) + +Now, you have the AppBinding that holds the connection information of the Vault server. + +```bash +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + labels: + app: vault + vault_cluster: vault + name: vault + namespace: demo +spec: + clientConfig: + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9URXhNRGN3TXpVNE1qZGFGdzB5T1RFeE1EUXdNelU0TWpkYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdVFaUWZNU1pZek13djUzQjlKcmJlZkc0ClREYmtuaERGamZNMmJrdU90ak83cElFdG5ZSzRrVEdDRkRGd1RlTUNoczhiNFBQcGN5YzBZZ3BSdFFYMW9VTGUKdTFCOE0ralBtMXdhYys4S0JGR3BJdjVpS2dzMjI1MWczTThoY0lqK0ZFQ3hMVTN1bHZDazlUSXlJYzNLSGlDcwpFUmg2VXA2V1hxSVJYb3loNlViWmFrd2tsUTd5SGdUY0ZQMzNzNlBVVXVZaFNtUTJBNmxPU2NPSFRaVytHVDNrCjdPSzUxQ3g5RUptcjdZY1J2N3RiNXI0bGYycy81ZGg0SnYwS2UySkNCUExoK0dBeVh2cHlMd1dmc0w3cWduZ28KZSt0SXVadXFsSENwWDN1eERILzBncGRtK0NHTkN0aUlZUzdGOEFQODlsVVdrc2JOcVdKL1RnTlIrYmp6WHdJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFGb0QvMGtZSHk5OW96MU9xSEVOOC9UVjVXM0dIN1lZSUdqVHZ5Mmc2NFpsajNDbjQKdHdlejd3VGhtMGllazFSR1VXM3luNzg2cEswZVFqYWM3OWZpUG5iTEx0WkRVTzFkSVM5Rnp1MmFiNmpITEpxYQpteUswcHJ1NGNDbmtZTmtOdWhKclQwSkl4Rjc5cXBEanlhSjVuOUxXbDFQZmZwZDZrUW5vdjZrNGtQL2JoTXhECk9oWVBvaVcydkZxSEI4NCtPVHhLbHRkWnNwTkR3bEh1NjZ6a1c0Z0xiRVBnTWUzN1p3NUFISWZld2hqWG93VHYKNVZpZnZYUjVreVNZTTdCMHlqcnpzUzNvK1ZGdS9wMzdmWThwaHMwZzdCWjd3TlhCcWJBT010K2s0Vy9CU0xUagpOelB2STB0SGFCTklnRFdHbm1waEIxN1BpQnBPc1Y2RHdiOVRYdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + service: + name: vault + port: 8200 + scheme: HTTPS + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: kubernetes + vaultRole: vault-policy-controller + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true +``` + +## VaultPolicy + +![Vault Policy](/docs/v2025.11.21/images/guides/policy-management/vault_policy.svg) + +Using VaultPolicy, you can create, update and delete policy in Vault. In this tutorial, we are going to create `read-only-policy` in `demo` namespace with the permissions to read and list Vault policies. + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: read-only-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "sys/policy" { + capabilities = ["list"] + } + + path "sys/policy/*" { + capabilities = ["read"] + } +``` + +Now, we are going to create VaultPolicy. + +```bash +$ kubectl apply -f docs/examples/guides/policy-management/read-only-policy.yaml +vaultpolicy.policy.kubevault.com/read-only-policy created +``` + +Check whether the VaultPolicy is successful. + +```cosole +$ kubectl get vaultpolicy -n demo +NAME PHASE AGE +read-only-policy Success 15s +``` + +Check whether the policy is created in the Vault server. To resolve the naming conflict, name of policy in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. In this case, it is `k8s.-.demo.read-only-policy`. + +> Don't have Vault CLI? Enable Vault CLI from [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli). + +```bash +$ vault list sys/policy +Keys +---- +k8s.-.demo.read-only-policy +... ... + +$ vault read sys/policy/k8s.-.demo.read-only-policy +Key Value +--- ----- +name k8s.-.demo.read-only-policy +rules path "sys/policy" { + capabilities = ["list"] +} + +path "sys/policy/*" { + capabilities = ["read"] +} +``` + +If we delete VaultPolicy `read-only-policy`, then the respective Vault policy will also be deleted from Vault. + +```cosole +$ kubectl delete vaultpolicies/read-only-policy -n demo +vaultpolicy.policy.kubevault.com "read-only-policy" deleted +``` + +Check whether the policy is deleted in Vault. + +```bash +$ vault read sys/policy/k8s.-.demo.read-only-policy +No value found at sys/policy/k8s.-.demo.read-only-policy + +$ vault list sys/policy +Keys +---- +default +k8s.-.demo.vault-auth-method-controller +root +vault-policy-controller +``` + +## VaultPolicyBinding + +![Vault Policy](/docs/v2025.11.21/images/guides/policy-management/vault_policy_binding.svg) + +Using VaultPolicyBinding, you can create an auth method role that binds the Vault policies to users or service accounts. + +Currently supported auth methods for creating role: + +- [Kubernetes Auth Method](https://www.vaultproject.io/docs/auth/kubernetes.html) + +In this tutorial, we are going to create a `policy-reader-role` VaultPolicyBinding in `demo` namespace. + +Create a service account in the demo namespace: + +```bash +$ kubectl create serviceaccount -n demo demo-sa +serviceaccount/demo-sa created +``` + +Get JWT token of the `demo-sa` service account: + +```bash +$ kubectl get secret -n demo demo-sa-token-jz7x5 -o jsonpath="{.data.token}" | base64 -d +eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZW1vIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlbW8tc2EtdG9rZW4tano3eDUiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVtby1zYSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjQxMGE4M2ViLWJhMDMtNDY1OS1iOTVjLTlmM2Y3ODdmZTM0OCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZW1vOmRlbW8tc2EifQ.w2H7cUXxAjeY4ZGJYVuTK8XrhpCXZeqUPQhFAyTndWhcevXOJFnK7jtyceYWaN0zy6TkBxHeAzVQdyLaFrNgecUKTzCZGaWHAoXlJOMY4Q49mHzEf3iGOBM7m1ckTTP9ABcOsVjD7OvlKslse_NnMDxVtuiughtMcrIhK5pbngQbJRpGkHaiOjgzIpHR3ybLmak7a24CXif0ZAqZd_y5l7bKi8eLr2Sidgq1R1sOMtOpnrj7qQCownw_KRrSPqhSCVSmaNDEYeqA9Jbw-JWVb3SW-FodjTPJsKj_qv791dZZE910CMBcsuJMPuAvNlX0cpOqO-7cdJzNG5y7IoYiSA +``` + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: policy-reader-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: read-only-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "demo-sa" + serviceAccountNamespaces: + - "demo" +``` + +Here, a Kubernetes auth method role will be created that binds the `read-only-policy` policy to the service account `demo-sa` in `demo` namespace. + +Let's create `read-only-policy` by using VaultPolicy: + +```bash +$ kubectl apply -f docs/examples/guides/policy-management/demo-policy.yaml +vaultpolicy.policy.kubevault.com/read-only-policy created +``` + +Check status: + +```bash +$ kubectl get vaultpolicy -n demo +NAME PHASE AGE +read-only-policy Success 15s +``` + +Now, we are going to create VaultPolicyBinding `policy-reader-role`. + +```cosole +$ kubectl apply -f docs/examples/guides/policy-management/policy-reader-role.yaml +vaultpolicybinding.policy.kubevault.com/policy-reader-role created +``` + +Check whether the `policy-reader-role` is successful. + +```bash +$ kubectl get vaultpolicybinding -n demo +NAME PHASE AGE +policy-reader-role Success 11s +``` + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/policy-management/../vault-server/vault-server#enable-vault-cli). + +Check whether the Kubernetes auth role is created in Vault. To resolve the naming conflict,name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. In this case, it is `k8s.-.demo.policy-reader-role`. + +```bash +$ vault list auth/kubernetes/role +Keys +---- +k8s.-.demo.policy-reader-role +k8s.-.demo.vault-auth-method-controller +vault-policy-controller + + +$ vault read auth/kubernetes/role/k8s.-.demo.policy-reader-role +Key Value +--- ----- +bound_service_account_names [demo-sa] +bound_service_account_namespaces [demo] +policies [k8s.-.demo.read-only-policy] +token_bound_cidrs [] +token_explicit_max_ttl 0s +token_max_ttl 0s +token_no_default_policy false +token_num_uses 0 +token_period 0s +token_policies [k8s.-.demo.read-only-policy] +token_ttl 0s +token_type default +``` + +Now, we are going to perform authentication to the Vault using `demo-sa`'s JWT token. In response to successful authentication, the Vault will provide us a token that will have permissions of the `read-only-policy` policy. + +```bash +$ vault write auth/kubernetes/login \ + role=k8s.-.demo.policy-reader-role \ + jwt=eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZW1vIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlbW8tc2EtdG9rZW4tano3eDUiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVtby1zYSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjQxMGE4M2ViLWJhMDMtNDY1OS1iOTVjLTlmM2Y3ODdmZTM0OCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZW1vOmRlbW8tc2EifQ.w2H7cUXxAjeY4ZGJYVuTK8XrhpCXZeqUPQhFAyTndWhcevXOJFnK7jtyceYWaN0zy6TkBxHeAzVQdyLaFrNgecUKTzCZGaWHAoXlJOMY4Q49mHzEf3iGOBM7m1ckTTP9ABcOsVjD7OvlKslse_NnMDxVtuiughtMcrIhK5pbngQbJRpGkHaiOjgzIpHR3ybLmak7a24CXif0ZAqZd_y5l7bKi8eLr2Sidgq1R1sOMtOpnrj7qQCownw_KRrSPqhSCVSmaNDEYeqA9Jbw-JWVb3SW-FodjTPJsKj_qv791dZZE910CMBcsuJMPuAvNlX0cpOqO-7cdJzNG5y7IoYiSA +Key Value +--- ----- +token s.0of6p1q8SrcN3OscDaBlmWuI +token_accessor lvddBe41uXe0DK5xGoaPKsN7 +token_duration 768h +token_renewable true +token_policies ["default" "k8s.-.demo.read-only-policy"] +identity_policies [] +policies ["default" "k8s.-.demo.read-only-policy"] +token_meta_role k8s.-.demo.policy-reader-role +token_meta_service_account_name demo-sa +token_meta_service_account_namespace demo +token_meta_service_account_secret_name demo-sa-token-jz7x5 +token_meta_service_account_uid 410a83eb-ba03-4659-b95c-9f3f787fe348 +``` + +Grab the token and export it as env to check its behavior: + +```bash +$ export VAULT_TOKEN=s.0of6p1q8SrcN3OscDaBlmWuI + +$ vault list sys/policy +Keys +---- +default +k8s.-.demo.read-only-policy +k8s.-.demo.vault-auth-method-controller +root +vault-policy-controller + +$ vault read sys/policy/k8s.-.demo.read-only-policy +Key Value +--- ----- +name k8s.-.demo.read-only-policy +rules path "sys/policy" { + capabilities = ["list"] +} + +path "sys/policy/*" { + capabilities = ["read"] +} + +$ vault delete sys/policy/k8s.-.demo.read-only-policy +Error deleting sys/policy/k8s.-.demo.read-only-policy: Error making API request. + +URL: DELETE https://127.0.0.1:8200/v1/sys/policy/k8s.-.demo.read-only-policy +Code: 403. Errors: + +* 1 error occurred: + * permission denied + +$ vault list auth/kubernetes/role +Error listing auth/kubernetes/role/: Error making API request. + +URL: GET https://127.0.0.1:8200/v1/auth/kubernetes/role?list=true +Code: 403. Errors: + +* 1 error occurred: + * permission denied + +``` + +Here, we can see that we don't have the permission to do anything but list and read the policies. So, the VaultPolicy `read-only-policy` and the VaultPolicyBinding `policy-reader-role` are working perfectly. + +If we delete VaultPolicyBinding, then the respective role will be deleted from Vault. + +```bash +$ kubectl delete vaultpolicybinding policy-reader-role -n demo +vaultpolicybinding.policy.kubevault.com "policy-reader-role" deleted +``` + +Check whether the role is deleted from Vault. + +```bash +$ vault read auth/kubernetes/role/k8s.-.demo.policy-reader-role +No value found at auth/kubernetes/role/k8s.-.demo.policy-reader-role + +$ vault list auth/kubernetes/role +Keys +---- +k8s.-.demo.vault-auth-method-controller +vault-policy-controller +``` diff --git a/content/docs/v2025.11.21/guides/secret-engines/_index.md b/content/docs/v2025.11.21/guides/secret-engines/_index.md new file mode 100755 index 000000000..984c1f07b --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/_index.md @@ -0,0 +1,17 @@ +--- +title: Secret Engine Guides | KubeVault +menu: + docs_v2025.11.21: + identifier: secret-engines-guides + name: Secret Engines + parent: guides + weight: 30 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/secret-engines/aws/_index.md b/content/docs/v2025.11.21/guides/secret-engines/aws/_index.md new file mode 100755 index 000000000..341f2c941 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/aws/_index.md @@ -0,0 +1,17 @@ +--- +title: AWS | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: aws-secret-engines + name: AWS + parent: secret-engines-guides + weight: 10 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/secret-engines/aws/csi-driver.md b/content/docs/v2025.11.21/guides/secret-engines/aws/csi-driver.md new file mode 100644 index 000000000..fa998692b --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/aws/csi-driver.md @@ -0,0 +1,293 @@ +--- +title: Mount AWS IAM Secrets using CSI Driver +menu: + docs_v2025.11.21: + identifier: csi-driver-aws + name: CSI Driver + parent: aws-secret-engines + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Mount AWS IAM Secrets using CSI Driver + +## Kubernetes Secrets Store CSI Driver + +Secrets Store CSI driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a [Container Storage Interface (CSI)](https://kubernetes-csi.github.io/docs/) volume. + +The Secrets Store CSI driver `secrets-store.csi.k8s.io` allows Kubernetes to mount multiple secrets, keys, and certs stored in enterprise-grade external secrets stores into their pods as a volume. Once the Volume is attached, the data in it is mounted into the container’s file system. + +![Secrets-store CSI architecture](/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg) + +When the `Pod` is created through the K8s API, it’s scheduled on to a node. The `kubelet` process on the node looks at the pod spec & see if there's any `volumeMount` request. The `kubelet` issues an `RPC` to the `CSI driver` to mount the volume. The `CSI driver` creates & mounts `tmpfs` into the pod. Then the `CSI driver` issues a request to the `Provider`. The provider talks to the external secrets store to fetch the secrets & write them to the pod volume as files. At this point, volume is successfully mounted & the pod starts running. + +You can read more about the Kubernetes Secrets Store CSI Driver [here](https://secrets-store-csi-driver.sigs.k8s.io/). + +## Consuming Secrets + +At first, you need to have a Kubernetes 1.16 or later cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). To check the version of your cluster, run: + +```bash +$ kubectl version --short +Client Version: v1.21.2 +Server Version: v1.21.1 +``` + +Before you begin: + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). +- Install Secrets Store CSI driver for Kubernetes secrets in your cluster from [here](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html). +- Install Vault Specific CSI provider from [here](https://github.com/hashicorp/vault-csi-provider) + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial stored in [examples](/docs/v2025.11.21/examples/guides/secret-engines/aws) folder in GitHub repository [KubeVault/docs](https://github.com/kubevault/kubevault) + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. And we also have the service account that the Vault server can authenticate. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable & Configure AWS SecretEngine + +### Enable AWS SecretEngine + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/aws/secretengine.yaml +secretengine.engine.kubevault.com/aws-engine created +``` + +### Create AWSRole + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/aws/secretenginerole.yaml +gcprole.engine.kubevault.com/aws-role created +``` + +Let's say pod's service account name is `test-user-account` located in `demo` namespace. We need to create a [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) and a [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) so that the pod has access to read secrets from the Vault server. + +### Create Service Account for Pod + +Let's create the service account `test-user-account` which will be used in VaultPolicyBinding. +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/aws/serviceaccount.yaml +serviceaccount/test-user-account created + +$ kubectl get serviceaccount -n demo +NAME SECRETS AGE +test-user-account 1 4h10m +``` + +### Create SecretRoleBinding for Pod's Service Account + +SecretRoleBinding will create VaultPolicy and VaultPolicyBinding inside vault. +When a VaultPolicyBinding object is created, the KubeVault operator create an auth role in the Vault server. The role name is generated by the following naming format: `k8s.(clusterName or -).namespace.name`. Here, it is `k8s.kubevault.com.demo.postgres-superuser-role`. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: AWSRole + name: aws-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo +``` + +Let's create SecretRoleBinding: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/aws/secret-role-binding.yaml +secretrolebinding.engine.kubevault.com/secret-role-binding created +``` +Check if the VaultPolicy and the VaultPolicyBinding are successfully registered to the Vault server: + +```bash +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 8s + +$ kubectl get vaultpolicybinding -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 10s +``` + +## Mount secrets into a Kubernetes pod + +So, we can create `SecretProviderClass` now. You can read more about `SecretProviderClass` [here](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#secretproviderclass). + +### Create SecretProviderClass + +Create `SecretProviderClass` object with the following content: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.aws-reader-role" + objects: | + - objectName: "access_key" + secretPath: "your-aws-path/creds/k8s.-.demo.aws-role" + secretKey: "access_key" + - objectName: "secret_key" + secretPath: "your-aws-path/creds/k8s.-.demo.aws-role" + secretKey: "secret_key" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/aws/secretproviderclass.yaml +secretproviderclass.secrets-store.csi.x-k8s.io/vault-db-provider created +``` +NOTE: The `SecretProviderClass` needs to be created in the same namespace as the pod. + +### Create Pod + +Now we can create a `Pod` to consume the `AWS` secrets. When the `Pod` is created, the `Provider` fetches the secret and writes them to Pod's volume as files. At this point, the volume is successfully mounted and the `Pod` starts running. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/aws-keys" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/aws/pod.yaml +pod/demo-app created +``` +## Test & Verify + +Check if the Pod is running successfully, by running: + +```bash +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +demo-app 1/1 Running 0 11s +``` + +### Verify Secret + +If the Pod is running successfully, then check inside the app container by running + +```bash +$ kubectl exec -it -n demo pod/demo-app -- /bin/sh +/ # ls /secrets-store/aws-keys +access_key secret_key + +/ # cat /secrets-store/aws-keys/access_key +AKIAWSY.... + +/ # cat /secrets-store/aws-keys/secret_key +sGOEbfiDwOL5Wke...... +/ # exit +``` + +So, we can see that the secret `access_key` & `secret_key` is mounted into the pod, where the secret key is mounted as file and value is the content of that file. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted +``` diff --git a/content/docs/v2025.11.21/guides/secret-engines/aws/overview.md b/content/docs/v2025.11.21/guides/secret-engines/aws/overview.md new file mode 100644 index 000000000..61715f75c --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/aws/overview.md @@ -0,0 +1,363 @@ +--- +title: Manage AWS IAM Secrets using the KubeVault operator +menu: + docs_v2025.11.21: + identifier: overview-aws + name: Overview + parent: aws-secret-engines + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Manage AWS IAM Secrets using the KubeVault operator + +The AWS secrets engine generates AWS access credentials dynamically based on IAM policies. The AWS IAM credentials are time-based and are automatically revoked when the Vault lease expires. You can easily manage the [AWS secret engine](https://www.vaultproject.io/docs/secrets/aws/index.html) using KubeVault operator. + +![AWS secret engine](/docs/v2025.11.21/images/guides/secret-engines/aws/aws_secret_engine_guide.svg) + +You need to be familiar with the following CRDs: + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) +- [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) +- [AWSRole](/docs/v2025.11.21/concepts/secret-engine-crds/aws-secret-engine/awsrole) + +## Before you begin + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +In this tutorial, we are going to create a [role](https://www.vaultproject.io/api/secret/aws/index.html#create-update-role) using AWSRole and issue credential using SecretAccessRequest. + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable and Configure AWS Secret Engine + +When a [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) crd object is created, the KubeVault operator will enable a secret engine on specified path and configure the secret engine with given configurations. + +A sample SecretEngine object for AWS secret engine: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: aws-secret-engine + namespace: demo +spec: + vaultRef: + name: vault + aws: + credentialSecret: aws-cred + region: us-east-1 + leaseConfig: + lease: 1h + leaseMax: 1h +``` + +To configure the AWS secret engine, you need to provide `aws_access_key_id` and `aws_secret_access_key` through a Kubernetes secret. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: aws-cred + namespace: demo +data: + access_key: eyJtc2ciOiJleGFtcGxlIn0= # base64 encoded aws access key id + secret_key: eyJtc2ciOiJleGFtcGxlIn0= # base64 encoded aws secret access key +``` + +Let's deploy SecretEngine: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/aws/secret.yaml +secret/aws-cred created + +$ kubectl apply -f docs/examples/guides/secret-engines/aws/secretengine.yaml +secretengine.engine.kubevault.com/aws-secret-engine created +``` + +Wait till the status become `Success`: + +```bash +$ kubectl get secretengines -n demo +NAME STATUS +aws-secret-engine Success +``` + +Since the status is `Success`, the AWS secret engine is enabled and successfully configured. You can use `kubectl describe secretengine -n ` to check for error events if any. + +## Create AWS Role + +By using [AWSRole](/docs/v2025.11.21/concepts/secret-engine-crds/aws-secret-engine/awsrole), you can create a [role](https://www.vaultproject.io/api/secret/aws/index.html#create-update-role) on the Vault server in Kubernetes native way. + +A sample AWSRole object is given below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: AWSRole +metadata: + name: aws-role + namespace: demo +spec: + secretEngineRef: + name: aws-secret-engine + credentialType: iam_user + policyDocument: | + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "ec2:*", + "Resource": "*" + } + ] + } +``` + +Let's deploy AWSRole: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/aws/secretenginerole.yaml +awsrole.engine.kubevault.com/aws-role created + +$ kubectl get awsrole -n demo +NAME STATUS +aws-role Success +``` + +You can also check from Vault that the role is created. +To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +```bash +$ vault list your-aws-path/roles +Keys +---- +k8s.-.demo.aws-role + +$ vault read your-aws-path/roles/k8s.-.demo.aws-role +Key Value +--- ----- +credential_type iam_user +default_sts_ttl 0s +iam_groups +iam_tags +max_sts_ttl 0s +permissions_boundary_arn n/a +policy_arns +policy_document {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"ec2:*","Resource":"*"}]} +role_arns +user_path n/a +``` + +If we delete the AWSRole, then the respective role will be deleted from the Vault. + +```bash +$ kubectl delete awsrole -n demo aws-role +awsrole.engine.kubevault.com "aws-role" deleted +``` + +Check from Vault whether the role exists: + +```bash +$ vault read your-aws-path/roles/k8s.-.demo.aws-role +No value found at your-aws-path/roles/k8s.-.demo.aws-role + +$ vault list aws/roles +No value found at aws/roles/ +``` + +## Generate AWS credentials + +Here, we are going to make a request to Vault for AWS credential by creating `aws-cred-rqst` SecretAccessRequest in `demo` namespace. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: aws-cred-rqst + namespace: demo +spec: + roleRef: + kind: AWSRole + name: aws-role + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +``` + +Here, `spec.roleRef` is the reference of AWSRole against which credentials will be issued. `spec.subjects` is the reference to the object or user identities a role binding applies to and it will have read access of the credential secret. + +Now, we are going to create an SecretAccessRequest. + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/aws/secretaccessrequest.yaml +secretaccessrequest.engine.kubevault.com/aws-cred-rqst created + +$ kubectl get secretaccessrequest -n demo +NAME AGE +aws-cred-rqst 35s +``` + +AWS credentials will not be issued until it is approved. The KubeVault operator will watch for the approval in the `status.conditions[].type` field of the request object. You can use [KubeVault CLI](https://github.com/kubevault/cli), a [kubectl plugin](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/), to approve or deny SecretAccessRequest. + +```bash +# using KubeVault CLI as kubectl plugin to approve request +$ kubectl vault approve secretaccessrequest aws-cred-rqst -n demo + approved + +$ kubectl get secretaccessrequest -n demo aws-cred-rqst -o yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: aws-cred-rqst + namespace: demo +spec: + roleRef: + name: aws-role + namespace: demo + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +status: + conditions: + - lastUpdateTime: "2019-11-13T12:18:07Z" + message: This was approved by kubectl vault approve secretaccessrequest + reason: KubectlApprove + type: Approved + lease: + duration: 1h0m0s + id: your-aws-path/creds/k8s.-.demo.aws-role/X9dCjtiQCykbuJ7UmzM64xfh + renewable: true + secret: + name: aws-cred-rqst-ryym7w +``` + +Once SecretAccessRequest is approved, the KubeVault operator will issue credentials from Vault and create a secret containing the credential. It will also create a role and rolebinding so that `spec.subjects` can access secret. You can view the information in the `status` field. + +```bash +$ kubectl get secretaccessrequest aws-cred-rqst -n demo -o json | jq '.status' +{ + "conditions": [ + { + "lastUpdateTime": "2019-11-13T12:18:07Z", + "message": "This was approved by kubectl vault approve secretaccessrequest", + "reason": "KubectlApprove", + "type": "Approved" + } + ], + "lease": { + "duration": "1h0m0s", + "id": "your-aws-path/creds/k8s.-.demo.aws-role/X9dCjtiQCykbuJ7UmzM64xfh", + "renewable": true + }, + "secret": { + "name": "aws-cred-rqst-ryym7w" + } +} + +$ kubectl get secret -n demo aws-cred-rqst-ryym7w -o yaml +apiVersion: v1 +data: + access_key: QUtJQVdTWV....= + secret_key: RVA1dXdXWnVlTX....== + security_token: "" +kind: Secret +metadata: + name: aws-cred-rqst-ryym7w + namespace: demo + ownerReferences: + - apiVersion: engine.kubevault.com/v1alpha1 + controller: true + kind: SecretAccessRequest + name: aws-cred-rqst +type: Opaque +``` + +If SecretAccessRequest is deleted, then credential lease (if any) will be revoked. + +```bash +$ kubectl delete secretaccessrequest -n demo aws-cred-rqst +secretaccessrequest.engine.kubevault.com "aws-cred-rqst" deleted +``` + +If SecretAccessRequest is `Denied`, then the KubeVault operator will not issue any credential. + +```bash +$ kubectl vault deny secretaccessrequest aws-cred-rqst -n demo + Denied +``` + +> Note: Once SecretAccessRequest is `Approved`, you can not change `spec.roleRef` and `spec.subjects` field. diff --git a/content/docs/v2025.11.21/guides/secret-engines/azure/_index.md b/content/docs/v2025.11.21/guides/secret-engines/azure/_index.md new file mode 100755 index 000000000..4fa0e6ae6 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/azure/_index.md @@ -0,0 +1,17 @@ +--- +title: Azure | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: azure-secret-engines + name: Azure + parent: secret-engines-guides + weight: 10 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/secret-engines/azure/csi-driver.md b/content/docs/v2025.11.21/guides/secret-engines/azure/csi-driver.md new file mode 100644 index 000000000..793745e4a --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/azure/csi-driver.md @@ -0,0 +1,293 @@ +--- +title: Mount Azure Secrets using CSI Driver +menu: + docs_v2025.11.21: + identifier: csi-driver-azure + name: CSI Driver + parent: azure-secret-engines + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Mount Azure Secrets using CSI Driver + +## Kubernetes Secrets Store CSI Driver + +Secrets Store CSI driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a [Container Storage Interface (CSI)](https://kubernetes-csi.github.io/docs/) volume. + +The Secrets Store CSI driver `secrets-store.csi.k8s.io` allows Kubernetes to mount multiple secrets, keys, and certs stored in enterprise-grade external secrets stores into their pods as a volume. Once the Volume is attached, the data in it is mounted into the container’s file system. + +![Secrets-store CSI architecture](/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg) + +When the `Pod` is created through the K8s API, it’s scheduled on to a node. The `kubelet` process on the node looks at the pod spec & see if there's any `volumeMount` request. The `kubelet` issues an `RPC` to the `CSI driver` to mount the volume. The `CSI driver` creates & mounts `tmpfs` into the pod. Then the `CSI driver` issues a request to the `Provider`. The provider talks to the external secrets store to fetch the secrets & write them to the pod volume as files. At this point, volume is successfully mounted & the pod starts running. + +You can read more about the Kubernetes Secrets Store CSI Driver [here](https://secrets-store-csi-driver.sigs.k8s.io/). + +## Consuming Secrets + +At first, you need to have a Kubernetes 1.16 or later cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). To check the version of your cluster, run: + +```bash +$ kubectl version --short +Client Version: v1.21.2 +Server Version: v1.21.1 +``` + +Before you begin: + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). +- Install Secrets Store CSI driver for Kubernetes secrets in your cluster from [here](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html). +- Install Vault Specific CSI provider from [here](https://github.com/hashicorp/vault-csi-provider) + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial stored in [examples](/docs/v2025.11.21/examples/guides/secret-engines/azure) folder in GitHub repository [KubeVault/docs](https://github.com/kubevault/kubevault) + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. And we also have the service account that the Vault server can authenticate. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable & Configure Azure SecretEngine + +### Enable Azure SecretEngine + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/azure/secretengine.yaml +secretengine.engine.kubevault.com/azure-engine created +``` + +### Create AzureRole + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/azure/secretenginerole.yaml +azurerole.engine.kubevault.com/azure-role created +``` + +Let's say pod's service account name is `test-user-account` located in `demo` namespace. We need to create a [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) and a [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) so that the pod has access to read secrets from the Vault server. + +### Create Service Account for Pod + +Let's create the service account `test-user-account` which will be used in VaultPolicyBinding. +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/azure/serviceaccount.yaml +serviceaccount/test-user-account created + +$ kubectl get serviceaccount -n demo +NAME SECRETS AGE +test-user-account 1 4h10m +``` + +### Create SecretRoleBinding for Pod's Service Account + +SecretRoleBinding will create VaultPolicy and VaultPolicyBinding inside vault. +When a VaultPolicyBinding object is created, the KubeVault operator create an auth role in the Vault server. The role name is generated by the following naming format: `k8s.(clusterName or -).namespace.name`. Here, it is `k8s.kubevault.com.demo.postgres-superuser-role`. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: AzureRole + name: azure-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo +``` + +Let's create SecretRoleBinding: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/azure/secret-role-binding.yaml +secretrolebinding.engine.kubevault.com/secret-role-binding created +``` +Check if the VaultPolicy and the VaultPolicyBinding are successfully registered to the Vault server: + +```bash +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 8s + +$ kubectl get vaultpolicybinding -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 10s +``` + +## Mount secrets into a Kubernetes pod + +So, we can create `SecretProviderClass` now. You can read more about `SecretProviderClass` [here](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#secretproviderclass). + +### Create SecretProviderClass + +Create `SecretProviderClass` object with the following content: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.azure-reader-role" + objects: | + - objectName: "client_id" + secretPath: "your-azure-path/creds/k8s.-.demo.azure-role" + secretKey: "client_id" + - objectName: "client_secret" + secretPath: "your-azure-path/creds/k8s.-.demo.azure-role" + secretKey: "client_secret" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/azure/secretproviderclass.yaml +secretproviderclass.secrets-store.csi.x-k8s.io/vault-db-provider created +``` +NOTE: The `SecretProviderClass` needs to be created in the same namespace as the pod. + +### Create Pod + +Now we can create a `Pod` to consume the `Azure` secrets. When the `Pod` is created, the `Provider` fetches the secret and writes them to Pod's volume as files. At this point, the volume is successfully mounted and the `Pod` starts running. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/azure-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/azure/pod.yaml +pod/demo-app created +``` +## Test & Verify + +Check if the Pod is running successfully, by running: + +```bash +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +demo-app 1/1 Running 0 11s +``` + +### Verify Secret + +If the Pod is running successfully, then check inside the app container by running + +```bash +$ kubectl exec -it -n demo pod/demo-app -- /bin/sh +/ # ls /secrets-store/azure-creds +client_id client_secret + +/ # cat /secrets-store/azure-creds/client_id +ya29.c.Kl20BwwWtb6DoTjY4-eSVgQQq....... + +/ # cat /secrets-store/azure-creds/client_secret +ya29.c.Kl20BwwWtb6DoTjY4-eSVgQQq....... +/ # exit +``` + +So, we can see that the secret `client_id` and `client_secret` is mounted into the pod, where the secret key is mounted as file and value is the content of that file. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted +``` diff --git a/content/docs/v2025.11.21/guides/secret-engines/azure/overview.md b/content/docs/v2025.11.21/guides/secret-engines/azure/overview.md new file mode 100644 index 000000000..ae409dcf8 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/azure/overview.md @@ -0,0 +1,361 @@ +--- +title: Manage Azure service principals using the KubeVault operator +menu: + docs_v2025.11.21: + identifier: overview-azure + name: Overview + parent: azure-secret-engines + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Manage Azure service principals using the KubeVault operator + +The Azure secrets engine dynamically generates Azure service principals and role assignments. Vault roles can be mapped to one or more Azure roles, providing a simple, flexible way to manage the permissions granted to generated service principals. You can easily manage the [Azure secret engine](https://www.vaultproject.io/docs/secrets/azure/index.html) using the KubeVault operator. + +![Azure secret engine](/docs/v2025.11.21/images/guides/secret-engines/azure/azure_secret_engine_guide.svg) + +You need to be familiar with the following CRDs: + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) +- [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) +- [AzureRole](/docs/v2025.11.21/concepts/secret-engine-crds/azure-secret-engine/azurerole) + +## Before you begin + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +In this tutorial, we are going to create a [role](https://www.vaultproject.io/api/secret/azure/index.html#create-update-role) using AzureRole and issue credential using SecretAccessRequest. + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable and Configure Azure Secret Engine + +When a [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) crd object is created, the KubeVault operator will enable a secret engine on specified path and configure the secret engine with given configurations. + +A sample SecretEngine object for Azure secret engine: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: azure-engine + namespace: demo +spec: + vaultRef: + name: vault + azure: + credentialSecret: azure-cred +``` + +To configure the Azure secret engine, you need to provide azure credentials through a Kubernetes secret. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: azure-cred + namespace: demo +data: + client-secret: eyJtc2ciOiJleGFtcGxlIn0= + subscription-id: eyJtc2ciOiJleGFtcGxlIn0= + client-id: eyJtc2ciOiJleGFtcGxlIn0= + tenant-id: eyJtc2ciOiJleGFtcGxlIn0= +``` + +Let's deploy SecretEngine: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/azure/secret.yaml +secret/azure-cred created + +$ kubectl apply -f docs/examples/guides/secret-engines/azure/secretengine.yaml +secretengine.engine.kubevault.com/azure-engine created +``` + +Wait till the status become `Success`: + +```bash +$ kubectl get secretengines -n demo +NAME STATUS +azure-engine Success +``` + +Since the status is `Success`, the Azure secret engine is enabled and successfully configured. You can use `kubectl describe secretengine -n ` to check for error events, if any. + +## Create Azure Role + +By using [AzureRole](/docs/v2025.11.21/concepts/secret-engine-crds/azure-secret-engine/azurerole), you can create a [role](https://www.vaultproject.io/api/secret/azure/index.html#create-update-role) on the Vault server in Kubernetes native way. + +A sample AzureRole object is given below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: AzureRole +metadata: + name: azure-role + namespace: demo +spec: + secretEngineRef: + name: vault + applicationObjectID: e211afbc-cc4a-462f-ad6f-59e26eb5406f + ttl: 1h +``` + +Let's deploy AzureRole: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/azure/secretenginerole.yaml +azurerole.engine.kubevault.com/azure-role created + +$ kubectl get azureroles -n demo +NAME STATUS +azure-role Success +``` + +You can also check from Vault that the role is created. +To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +```bash +$ vault list azure/roles +Keys +---- +k8s.-.demo.azure-role + +$ vault read azure/roles/k8s.-.demo.azure-role +Key Value +--- ----- +application_object_id c1cb042d-96d7-423a-8dba-243c2e5010d3 +azure_roles +max_ttl 0s +ttl 1h +``` + +If we delete the AzureRole, then the respective role will be deleted from the Vault. + +```bash +$ kubectl delete -f docs/examples/guides/secret-engines/azure/secretenginerole.yaml + azurerole.engine.kubevault.com "azure-role" deleted +``` + +Check from Vault whether the role exists: + +```bash +$ vault read azure/roles/k8s.-.demo.azure-role + No value found at azure/roles/k8s.-.demo.azure-role + +$ vault list azure/roles + No value found at azure/roles/ +``` + +## Generate Azure credentials + + +Here, we are going to make a request to Vault for Azure credentials by creating `azure-cred-rqst` SecretAccessRequest in `demo` namespace. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: azure-cred-rqst + namespace: demo +spec: + roleRef: + kind: AzureRole + name: azure-role + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +``` + +Here, `spec.roleRef` is the reference of AzureRole against which credentials will be issued. `spec.subjects` is the reference to the object or user identities a role binding applies to and it will have read access of the credential secret. + +Now, we are going to create SecretAccessRequest. + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/azure/azureaccessrequest.yaml +secretaccessrequest.engine.kubevault.com/azure-cred-rqst created + +$ kubectl get secretaccessrequests -n demo +NAME AGE +azure-cred-rqst 3s +``` + +Azure credentials will not be issued until it is approved. The KubeVault operator will watch for the approval in the `status.conditions[].type` field of the request object. You can use [KubeVault CLI](https://github.com/kubevault/cli), a [kubectl plugin](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/), to approve or deny SecretAccessRequest. + +```bash +# using KubeVault CLI as kubectl plugin to approve request +$ kubectl vault approve secretaccessrequest azure-cred-rqst -n demo + approved + +$ kubectl get secretaccessrequests -n demo azure-cred-rqst -o yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: azure-cred-rqst + namespace: demo +spec: + roleRef: + name: azure-role + namespace: demo + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +status: + conditions: + - lastUpdateTime: "2019-11-14T09:21:49Z" + message: This was approved by kubectl vault approve secretaccessrequest + reason: KubectlApprove + type: Approved + lease: + duration: 1h0m0s + id: azure/creds/k8s.-.demo.azure-role/FJVEWUW9NpGlFOdIIMd900Zr + renewable: true + secret: + name: azure-cred-rqst-luc5p4 + + +``` + +Once SecretAccessRequest is approved, the KubeVault operator will issue credentials from Vault and create a secret containing the credential. It will also create a role and rolebinding so that `spec.subjects` can access secret. You can view the information in the `status` field. + +```bash +$ kubectl get secretaccessrequest azure-cred-rqst -n demo -o json | jq '.status' +{ + "conditions": [ + { + "lastUpdateTime": "2019-11-14T09:21:49Z", + "message": "This was approved by kubectl vault approve secretaccessrequest", + "reason": "KubectlApprove", + "type": "Approved" + } + ], + "lease": { + "duration": "1h0m0s", + "id": "azure/creds/k8s.-.demo.azure-role/FJVEWUW9NpGlFOdIIMd900Zr", + "renewable": true + }, + "secret": { + "name": "azure-cred-rqst-luc5p4" + } +} + +$ kubectl get secret -n demo azure-cred-rqst-luc5p4 -o yaml +apiVersion: v1 +data: + client_id: MmI4NzFkNGEtN... + client_secret: ZjJlMjA3N... +kind: Secret +metadata: + name: azure-cred-rqst-luc5p4 + namespace: demo + ownerReferences: + - apiVersion: engine.kubevault.com/v1alpha1 + controller: true + kind: SecretAccessRequest + name: azure-cred-rqst + uid: d944491b-a22c-4777-bc8f-2e2c94b47b7b +type: Opaque + +``` + +If SecretAccessRequest is deleted, then credential lease (if any) will be revoked. + +```bash +$ kubectl delete secretaccessrequest -n demo azure-cred-rqst +secretaccessrequest.engine.kubevault.com "azure-cred-rqst" deleted +``` + +If SecretAccessRequest is `Denied`, then the KubeVault operator will not issue any credentials. + +```bash +$ kubectl vault deny secretaccessrequest azure-cred-rqst -n demo + Denied + +$ kubectl get secretaccessrequest azure-cred-rqst -n demo -o json | jq '.status' + { + "conditions": [ + { + "lastUpdateTime": "2019-11-14T09:21:49Z", + "message": "This was denied by kubectl vault deny secretaccessrequest", + "reason": "KubectlDeny", + "type": "Denied" + } + ] + } +``` + +> Note: Once SecretAccessRequest is `Approved` or `Denied`, you cannot change `spec.roleRef` and `spec.subjects` field. diff --git a/content/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg b/content/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg new file mode 100644 index 000000000..775afdf10 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/docs/v2025.11.21/guides/secret-engines/elasticsearch/_index.md b/content/docs/v2025.11.21/guides/secret-engines/elasticsearch/_index.md new file mode 100755 index 000000000..036a39733 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/elasticsearch/_index.md @@ -0,0 +1,17 @@ +--- +title: Elasticsearch | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: elasticsearch-secret-engines + name: Elasticsearch + parent: secret-engines-guides + weight: 20 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/secret-engines/elasticsearch/csi-driver.md b/content/docs/v2025.11.21/guides/secret-engines/elasticsearch/csi-driver.md new file mode 100644 index 000000000..e571e4876 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/elasticsearch/csi-driver.md @@ -0,0 +1,292 @@ +--- +title: Mount Elasticsearch Secrets using CSI Driver +menu: + docs_v2025.11.21: + identifier: csi-driver-elasticsearch + name: CSI Driver + parent: elasticsearch-secret-engines + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Mount Elasticsearch Secrets using CSI Driver + +## Kubernetes Secrets Store CSI Driver +Secrets Store CSI driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a [Container Storage Interface (CSI)](https://kubernetes-csi.github.io/docs/) volume. + +The Secrets Store CSI driver `secrets-store.csi.k8s.io` allows Kubernetes to mount multiple secrets, keys, and certs stored in enterprise-grade external secrets stores into their pods as a volume. Once the Volume is attached, the data in it is mounted into the container’s file system. + +![Secrets-store CSI architecture](/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg) + +When the `Pod` is created through the K8s API, it’s scheduled on to a node. The `kubelet` process on the node looks at the pod spec & see if there's any `volumeMount` request. The `kubelet` issues an `RPC` to the `CSI driver` to mount the volume. The `CSI driver` creates & mounts `tmpfs` into the pod. Then the `CSI driver` issues a request to the `Provider`. The provider talks to the external secrets store to fetch the secrets & write them to the pod volume as files. At this point, volume is successfully mounted & the pod starts running. + +You can read more about the Kubernetes Secrets Store CSI Driver [here](https://secrets-store-csi-driver.sigs.k8s.io/). + +## Consuming Secrets +At first, you need to have a Kubernetes 1.16 or later cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). To check the version of your cluster, run: + +```bash +$ kubectl version --short +Client Version: v1.21.2 +Server Version: v1.21.1 +``` + +Before you begin: + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). +- Install Secrets Store CSI driver for Kubernetes secrets in your cluster from [here](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html). +- Install Vault Specific CSI provider from [here](https://github.com/hashicorp/vault-csi-provider) + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial stored in [examples](/docs/v2025.11.21/examples/guides/secret-engines/elasticsearch) folder in GitHub repository [KubeVault/docs](https://github.com/kubevault/kubevault) + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. And we also have the service account that the Vault server can authenticate. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable & Configure Elasticsearch SecretEngine + +### Enable Elasticsearch SecretEngine + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/elasticsearch/secretengine.yaml +secretengine.engine.kubevault.com/es-engine created +``` + +### Create ElasticsearchRole + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/elasticsearch/secretenginerole.yaml +elasticsearchrole.engine.kubevault.com/es-superuser-role created +``` + +Let's say pod's service account name is `test-user-account` located in `demo` namespace. We need to create a [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) and a [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) so that the pod has access to read secrets from the Vault server. + +### Create Service Account for Pod + +Let's create the service account `test-user-account` which will be used in VaultPolicyBinding. +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/elasticsearch/serviceaccount.yaml +serviceaccount/test-user-account created + +$ kubectl get serviceaccount -n demo +NAME SECRETS AGE +test-user-account 1 4h10m +``` + +### Create SecretRoleBinding for Pod's Service Account + +SecretRoleBinding will create VaultPolicy and VaultPolicyBinding inside vault. +When a VaultPolicyBinding object is created, the KubeVault operator create an auth role in the Vault server. The role name is generated by the following naming format: `k8s.(clusterName or -).namespace.name`. Here, it is `k8s.kubevault.com.demo.postgres-superuser-role`. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: ElasticsearchRole + name: es-superuser-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo +``` + +Let's create SecretRoleBinding: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/elasticsearch/secret-role-binding.yaml +secretrolebinding.engine.kubevault.com/secret-role-binding created +``` +Check if the VaultPolicy and the VaultPolicyBinding are successfully registered to the Vault server: + +```bash +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 8s + +$ kubectl get vaultpolicybinding -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 10s +``` + +## Mount secrets into a Kubernetes pod + +So, we can create `SecretProviderClass` now. You can read more about `SecretProviderClass` [here](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#secretproviderclass). + +### Create SecretProviderClass + +Create `SecretProviderClass` object with the following content: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.es-reader-role" + objects: | + - objectName: "es-creds-username" + secretPath: "your-database-path/creds/k8s.-.demo.es-superuser-role" + secretKey: "username" + - objectName: "es-creds-password" + secretPath: "your-database-path/creds/k8s.-.demo.es-superuser-role" + secretKey: "password" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/elasticsearch/secretproviderclass.yaml +secretproviderclass.secrets-store.csi.x-k8s.io/vault-db-provider created +``` +NOTE: The `SecretProviderClass` needs to be created in the same namespace as the pod. + +### Create Pod + +Now we can create a `Pod` to consume the `Elasticsearch` secrets. When the `Pod` is created, the `Provider` fetches the secret and writes them to Pod's volume as files. At this point, the volume is successfully mounted and the `Pod` starts running. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/es-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/elasticsearch/pod.yaml +pod/demo-app created +``` +## Test & Verify + +Check if the Pod is running successfully, by running: + +```bash +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +demo-app 1/1 Running 0 11s +``` + +### Verify Secret + +If the Pod is running successfully, then check inside the app container by running + +```bash +$ kubectl exec -it -n demo pod/demo-app -- /bin/sh +/ # ls /secrets-store/es-creds +es-creds-password es-creds-username + +/ # cat /secrets-store/es-creds/es-creds-password +TAu2Zvg1WYE07W8Uf-nW + +/ # cat /secrets-store/es-creds/es-creds-username +v-kubernetes-test-k8s.-.demo.es-s-iPkxiH80Ollq2QgF82Ab-1629178048 + +/ # exit +``` + +So, we can see that the secret `db-username` and `db-password` is mounted into the pod, where the secret key is mounted as file and value is the content of that file. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted +``` diff --git a/content/docs/v2025.11.21/guides/secret-engines/elasticsearch/overview.md b/content/docs/v2025.11.21/guides/secret-engines/elasticsearch/overview.md new file mode 100644 index 000000000..088269879 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/elasticsearch/overview.md @@ -0,0 +1,337 @@ +--- +title: Manage Elasticsearch credentials using the KubeVault operator +menu: + docs_v2025.11.21: + identifier: overview-elasticsearch + name: Overview + parent: elasticsearch-secret-engines + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Manage Elasticsearch credentials using the KubeVault operator + +Elasticsearch is one of the supported plugins for the database secrets engine. This plugin generates database credentials dynamically based on configured roles for the Elasticsearch database. You can easily manage [Elasticsearch secret engine](https://www.vaultproject.io/docs/secrets/databases/elasticdb.html) using the KubeVault operator. + +![Elasticsearch secret engine](/docs/v2025.11.21/images/guides/secret-engines/elasticsearch/elasticsearch_secret_engine_guide.svg) + +You need to be familiar with the following CRDs: + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) +- [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) +- [ElasticsearchRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/elasticsearch) + +## Before you begin + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +In this tutorial, we are going to create a [role](https://www.vaultproject.io/docs/secrets/databases/elasticdb#setup) using Elasticsearch and issue credential using SecretAccessRequest. + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable and Configure Elasticsearch Secret Engine + +When a [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) crd object is created, the KubeVault operator will enable a secret engine on specified path and configure the secret engine with given configurations. + +A sample SecretEngine object for the Elasticsearch secret engine: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: es-engine + namespace: demo +spec: + vaultRef: + name: vault + elasticsearch: + databaseRef: + name: elasticsearch + namespace: demo + pluginName: "elasticsearch-database-plugin" +``` + +Let's deploy SecretEngine: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/elasticsearch/secretengine.yaml +secretengine.engine.kubevault.com/es-engine created +``` + +Wait till the status become `Success`: + +```bash +$ kubectl get secretengines -n demo +NAME STATUS AGE +es-engine Success 10s +``` + +Since the status is `Success`, the Elasticsearch secret engine is enabled and successfully configured. You can use `kubectl describe secretengine -n ` to check for error events, if any. + +## Create Elasticsearch Role + +By using [ElasticsearchRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/elasticsearch), you can create a [role](https://www.vaultproject.io/docs/secrets/databases/elasticdb#setup) on the Vault server in Kubernetes native way. + +A sample ElasticsearchRole object is given below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: ElasticsearchRole +metadata: + name: es-superuser-role + namespace: demo +spec: + secretEngineRef: + name: es-secret-engine + creationStatements: + - '{"elasticsearch_roles": ["superuser"]}' + defaultTTL: 1h + maxTTL: 24h +``` + +Let's deploy ElasticsearchRole: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/elasticsearch/secretenginerole.yaml +elasticsearchrole.engine.kubevault.com/es-superuser-role created + +$ kubectl get elasticsearchrole -n demo +NAME STATUS AGE +es-superuser-role Success 34m +``` + +You can also check from Vault that the role is created. +To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +```bash +$ vault list your-database-path/roles +Keys +---- +k8s.-.demo.es-superuser-role + +$ vault read your-database-path/roles/k8s.-.demo.es-superuser-role +Key Value +--- ----- +creation_statements [{"elasticsearch_roles": ["superuser"]}] +db_name k8s.-.demo.elasticsearch +default_ttl 1h +max_ttl 24h +renew_statements [] +revocation_statements [] +rollback_statements [] +``` + +If we delete the ElasticsearchRole, then the respective role will be deleted from the Vault. + +```bash +$ kubectl delete elasticsearchrole -n demo es-superuser-role +elasticsearchrole.engine.kubevault.com "es-superuser-role" deleted +``` + +Check from Vault whether the role exists: + +```bash +$ vault read your-database-path/roles/k8s.-.demo.es-superuser-role +No value found at your-database-path/roles/k8s.-.demo.es-superuser-role + +$ vault list your-database-path/roles +No value found at your-database-path/roles/ +``` + +## Generate Elasticsearch credentials + + +Here, we are going to make a request to Vault for Elasticsearch credentials by creating `es-cred-rqst` SecretAccessRequest in `demo` namespace. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: es-cred-rqst + namespace: demo +spec: + roleRef: + kind: ElasticsearchRole + name: es-superuser-role + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +``` + +Here, `spec.roleRef` is the reference of Elasticsearch against which credentials will be issued. `spec.subjects` is the reference to the object or user identities a role binding applies to it will have read access of the credential secret. + +Now, we are going to create SecretAccessRequest. + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/elasticsearch/elasticaccessrequest.yaml +secretaccessrequest.engine.kubevault.com/es-cred-rqst created + +$ kubectl get secretaccessrequest -n demo +NAME AGE +es-cred-rqst 72m +``` + +Database credentials will not be issued until it is approved. The KubeVault operator will watch for the approval in the `status.conditions[].type` field of the request object. You can use [KubeVault CLI](https://github.com/kubevault/cli), a [kubectl plugin](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/), to approve or deny SecretAccessRequest. + +```bash +# using KubeVault CLI as kubectl plugin to approve request +$ kubectl vault approve secretaccessrequest es-cred-rqst -n demo +approved + +$ kubectl get secretaccessrequest -n demo es-cred-rqst -o yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: es-cred-rqst + namespace: demo +spec: + roleRef: + kind: ElasticsearchRole + name: es-superuser-role + namespace: demo + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +status: + conditions: + - lastUpdateTime: "2020-11-18T06:41:57Z" + message: This was approved by kubectl vault approve secreteaccessrequest + reason: KubectlApprove + type: Approved + lease: + duration: 1h0m0s + id: your-database-path/creds/k8s.-.demo.es-superuser-role/ni3TCo2HkSwCUb8kmQuvIDdx + renewable: true + secret: + name: es-cred-rqst-gy66wq +``` + +Once SecretAccessRequest is approved, the KubeVault operator will issue credentials from Vault and create a secret containing the credential. It will also create a role and rolebinding so that `spec.subjects` can access secret. You can view the information in the `status` field. + +```bash +$ kubectl get secretaccessrequest es-cred-rqst -n demo -o json | jq '.status' +{ + "conditions": [ + { + "lastUpdateTime": "2019-11-18T06:41:57Z", + "message": "This was approved by kubectl vault approve secretaccessrequest", + "reason": "KubectlApprove", + "type": "Approved" + } + ], + "lease": { + "duration": "1h0m0s", + "id": "your-database-path/creds/k8s.-.demo.es-superuser-role/ni3TCo2HkSwCUb8kmQuvIDdx", + "renewable": true + }, + "secret": { + "name": "es-cred-rqst-gy66wq" + } +} + +$ kubectl get secret -n demo es-cred-rqst-gy66wq -o yaml +apiVersion: v1 +data: + password: QTFhLVBkZGlsZFFxa0o1cnlvR20= + username: di1rdWJlcm5ldGVzLWRlbW8TE1NzQwNTkzMTc= +kind: Secret +metadata: + name: es-cred-rqst-gy66wq + namespace: demo + ownerReferences: + - apiVersion: engine.kubevault.com/v1alpha1 + controller: true + kind: SecretAccessRequest + name: es-cred-rqst + uid: 54ce63ca-d0e7-4b97-9085-b52eb3cb334f +type: Opaque +``` + +If SecretAccessRequest is deleted, then credential lease (if any) will be revoked. + +```bash +$ kubectl delete secretaccessrequest -n demo es-cred-rqst +secretaccessrequest.engine.kubevault.com "es-cred-rqst" deleted +``` + +If SecretAccessRequest is `Denied`, then the KubeVault operator will not issue any credential. + +```bash +$ kubectl vault deny secretaccessrequest es-cred-rqst -n demo + Denied +``` + +> Note: Once SecretAccessRequest is `Approved`, you cannot change `spec.roleRef` and `spec.subjects` field. diff --git a/content/docs/v2025.11.21/guides/secret-engines/gcp/_index.md b/content/docs/v2025.11.21/guides/secret-engines/gcp/_index.md new file mode 100755 index 000000000..cab6af49b --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/gcp/_index.md @@ -0,0 +1,17 @@ +--- +title: GCP | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: gcp-secret-engines + name: GCP + parent: secret-engines-guides + weight: 10 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/secret-engines/gcp/csi-driver.md b/content/docs/v2025.11.21/guides/secret-engines/gcp/csi-driver.md new file mode 100644 index 000000000..b1ceadd9a --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/gcp/csi-driver.md @@ -0,0 +1,288 @@ +--- +title: Mount GCP Secrets using CSI Driver +menu: + docs_v2025.11.21: + identifier: csi-driver-gcp + name: CSI Driver + parent: gcp-secret-engines + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Mount GCP Secrets using CSI Driver + +## Kubernetes Secrets Store CSI Driver + +Secrets Store CSI driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a [Container Storage Interface (CSI)](https://kubernetes-csi.github.io/docs/) volume. + +The Secrets Store CSI driver `secrets-store.csi.k8s.io` allows Kubernetes to mount multiple secrets, keys, and certs stored in enterprise-grade external secrets stores into their pods as a volume. Once the Volume is attached, the data in it is mounted into the container’s file system. + +![Secrets-store CSI architecture](/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg) + +When the `Pod` is created through the K8s API, it’s scheduled on to a node. The `kubelet` process on the node looks at the pod spec & see if there's any `volumeMount` request. The `kubelet` issues an `RPC` to the `CSI driver` to mount the volume. The `CSI driver` creates & mounts `tmpfs` into the pod. Then the `CSI driver` issues a request to the `Provider`. The provider talks to the external secrets store to fetch the secrets & write them to the pod volume as files. At this point, volume is successfully mounted & the pod starts running. + +You can read more about the Kubernetes Secrets Store CSI Driver [here](https://secrets-store-csi-driver.sigs.k8s.io/). + +## Consuming Secrets + +At first, you need to have a Kubernetes 1.16 or later cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). To check the version of your cluster, run: + +```bash +$ kubectl version --short +Client Version: v1.21.2 +Server Version: v1.21.1 +``` + +Before you begin: + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). +- Install Secrets Store CSI driver for Kubernetes secrets in your cluster from [here](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html). +- Install Vault Specific CSI provider from [here](https://github.com/hashicorp/vault-csi-provider) + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial stored in [examples](/docs/v2025.11.21/examples/guides/secret-engines/gcp) folder in GitHub repository [KubeVault/docs](https://github.com/kubevault/kubevault) + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. And we also have the service account that the Vault server can authenticate. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable & Configure GCP SecretEngine + +### Enable GCP SecretEngine + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/gcp/secretengine.yaml +secretengine.engine.kubevault.com/gcp-engine created +``` + +### Create GCPRole + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/gcp/secretenginerole.yaml +gcprole.engine.kubevault.com/gcp-role created +``` + +Let's say pod's service account name is `test-user-account` located in `demo` namespace. We need to create a [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) and a [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) so that the pod has access to read secrets from the Vault server. + +### Create Service Account for Pod + +Let's create the service account `test-user-account` which will be used in VaultPolicyBinding. +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/gcp/serviceaccount.yaml +serviceaccount/test-user-account created + +$ kubectl get serviceaccount -n demo +NAME SECRETS AGE +test-user-account 1 4h10m +``` + +### Create SecretRoleBinding for Pod's Service Account + +SecretRoleBinding will create VaultPolicy and VaultPolicyBinding inside vault. +When a VaultPolicyBinding object is created, the KubeVault operator create an auth role in the Vault server. The role name is generated by the following naming format: `k8s.(clusterName or -).namespace.name`. Here, it is `k8s.kubevault.com.demo.postgres-superuser-role`. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: GCPRole + name: gcp-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo +``` + +Let's create SecretRoleBinding: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/gcp/secret-role-binding.yaml +secretrolebinding.engine.kubevault.com/secret-role-binding created +``` +Check if the VaultPolicy and the VaultPolicyBinding are successfully registered to the Vault server: + +```bash +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 8s + +$ kubectl get vaultpolicybinding -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 10s +``` + +## Mount secrets into a Kubernetes pod + +So, we can create `SecretProviderClass` now. You can read more about `SecretProviderClass` [here](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#secretproviderclass). + +### Create SecretProviderClass + +Create `SecretProviderClass` object with the following content: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.gcp-reader-role" + objects: | + - objectName: "gcp-token" + secretPath: "your-gcp-path/token/k8s.-.demo.gcp-role" + secretKey: "token" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/gcp/secretproviderclass.yaml +secretproviderclass.secrets-store.csi.x-k8s.io/vault-db-provider created +``` +NOTE: The `SecretProviderClass` needs to be created in the same namespace as the pod. + +### Create Pod + +Now we can create a `Pod` to consume the `GCP` secrets. When the `Pod` is created, the `Provider` fetches the secret and writes them to Pod's volume as files. At this point, the volume is successfully mounted and the `Pod` starts running. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/gcp-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/gcp/pod.yaml +pod/demo-app created +``` +## Test & Verify + +Check if the Pod is running successfully, by running: + +```bash +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +demo-app 1/1 Running 0 11s +``` + +### Verify Secret + +If the Pod is running successfully, then check inside the app container by running + +```bash +$ kubectl exec -it -n demo pod/demo-app -- /bin/sh +/ # ls /secrets-store/gcp-creds +gcp-token + +/ # cat /secrets-store/gcp-creds/gcp-token +ya29.c.Kl20BwwWtb6DoTjY4-eSVgQQq....... + +/ # exit +``` + +So, we can see that the secret `gcp-token` is mounted into the pod, where the secret key is mounted as file and value is the content of that file. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted +``` diff --git a/content/docs/v2025.11.21/guides/secret-engines/gcp/overview.md b/content/docs/v2025.11.21/guides/secret-engines/gcp/overview.md new file mode 100644 index 000000000..6d38fe35a --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/gcp/overview.md @@ -0,0 +1,343 @@ +--- +title: Manage GCP IAM Secrets using the KubeVault operator +menu: + docs_v2025.11.21: + identifier: overview-gcp + name: Overview + parent: gcp-secret-engines + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Manage GCP IAM Secrets using the KubeVault operator + +The Google Cloud Vault secrets engine dynamically generates Google Cloud service account keys and OAuth tokens based on IAM policies. This enables users to gain access to Google Cloud resources without needing to create or manage a dedicated service account. You can easily manage [GCP secret engine](https://www.vaultproject.io/docs/secrets/gcp/index.html) using the KubeVault operator. + +![GCP secret engine](/docs/v2025.11.21/images/guides/secret-engines/gcp/gcp_guide.svg) + +You need to be familiar with the following CRDs: + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) +- [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) +- [GCPRole](/docs/v2025.11.21/concepts/secret-engine-crds/gcp-secret-engine/gcprole) + +## Before you begin + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +In this tutorial, we are going to create a [role](https://www.vaultproject.io/api/secret/gcp/index.html#create-update-roleset) using GCPRole and issue credential using SecretAccessRequest. + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable and Configure GCP Secret Engine + +When a [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) crd object is created, the KubeVault operator will enable a secret engine on specified path and configure the secret engine with given configurations. + +A sample SecretEngine object for GCP secret engine: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: gcp-engine + namespace: demo +spec: + vaultRef: + name: vault + gcp: + credentialSecret: gcp-cred +``` + +To configure the GCP secret engine, you need to provide google service account credentials through a Kubernetes secret. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: gcp-cred + namespace: demo +data: + sa.json: eyJtc2ciOiJleGFtcGxlIn0= ## base64 encoded google service account credential +``` + +Let's deploy SecretEngine: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/gcp/secret.yaml +secret/gcp-cred created + +$ kubectl apply -f docs/examples/guides/secret-engines/gcp/secretengine.yaml +secretengine.engine.kubevault.com/gcp-engine created +``` + +Wait till the status become `Success`: + +```bash +$ kubectl get secretengines -n demo +NAME STATUS +gcp-engine Success +``` + +Since the status is `Success`, the GCP secret engine is enabled and successfully configured. You can use `kubectl describe secretengine -n ` to check for error events, if any. + +## Create GCP Roleset + +By using [GCPRole](/docs/v2025.11.21/concepts/secret-engine-crds/gcp-secret-engine/gcprole), you can [create gcp roleset](https://www.vaultproject.io/api/secret/gcp/index.html#create-update-roleset) on the Vault server in Kubernetes native way. + +A sample GCPRole object is given below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: GCPRole +metadata: + name: gcp-role + namespace: demo +spec: + secretEngineRef: + name: gcp-secret-engine + secretType: "access_token" + project: appscode-testing + bindings: | + resource "//cloudresourcemanager.googleapis.com/projects/appscode-testing" { + roles = ["roles/viewer"] + } + tokenScopes: + - https://www.googleapis.com/auth/cloud-platform +``` + +Let's deploy GCPRole: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/gcp/secretenginerole.yaml +gcprole.engine.kubevault.com/gcp-role created + +$ kubectl get gcprole -n demo +NAME STATUS +gcp-role Success +``` + +You can also check from Vault that the roleset is created. +To resolve the naming conflict, name of the roleset in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +```bash +$ vault list your-gcp-path/roleset +Keys +---- +k8s.-.demo.gcp-role + +$ vault read your-gcp-path/roleset/k8s.-.demo.gcp-role +Key Value +--- ----- +bindings map[//cloudresourcemanager.googleapis.com/projects/appscode-testing:[roles/viewer]] +project appscode-testing +secret_type access_token +service_account_email vaultk8s---demo-gcp-1629380381@appscode-testing.iam.gserviceaccount.com +token_scopes [https://www.googleapis.com/auth/cloud-platform] +``` + +If we delete the GCPRole, then the respective role will be deleted from the Vault. + +```bash +$ kubectl delete -f docs/examples/guides/secret-engines/gcp/secretenginerole.yaml + gcprole.engine.kubevault.com "gcp-role" deleted +``` + +Check from Vault whether the roleset exists: + +```bash +$ vault read your-gcp-path/roleset/k8s.-.demo.gcp-role + No value found at your-gcp-path/roleset/k8s.-.demo.gcp-role + +$ vault list your-gcp-path/roleset + No value found at your-gcp-path/roleset/ +``` + +## Generate GCP credentials + + +Here, we are going to make a request to Vault for GCP credential by creating `gcp-cred-req` SecretAccessRequest in `demo` namespace. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: gcp-cred-req + namespace: demo +spec: + roleRef: + kind: GCPRole + name: gcp-role + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +``` + +Here, `spec.roleRef` is the reference of GCPRole against which credentials will be issued. `spec.subjects` is the reference to the object or user identities a role binding applies to and it will have read access of the credential secret. + +Now, we are going to create SecretAccessRequest. + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/gcp/secretaccessrequest.yaml +secretaccessrequest.engine.kubevault.com/gcp-cred-req created + +$ kubectl get secretaccessrequests -n demo +NAME AGE +gcp-cred-req 3s +``` + +GCP credentials will not be issued until it is approved. The KubeVault operator will watch for the approval in the `status.conditions[].type` field of the request object. You can use [KubeVault CLI](https://github.com/kubevault/cli), a [kubectl plugin](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/), to approve or deny SecretAccessRequest. + +```bash +# using KubeVault CLI as kubectl plugin to approve request +$ kubectl vault approve secretaccessrequest gcp-cred-req -n demo + approved + +$ kubectl get secretaccessrequest -n demo gcp-cred-req -o yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: gcp-cred-req + namespace: demo +spec: + roleRef: + name: gcp-role + namespace: demo + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +status: + conditions: + - lastUpdateTime: "2019-11-12T10:40:30Z" + message: This was approved by kubectl vault approve secretaccessrequest + reason: KubectlApprove + type: Approved + lease: + duration: 0s + secret: + name: gcp-cred-req-unyzu6 + +``` + +Once SecretAccessRequest is approved, the KubeVault operator will issue credentials from Vault and create a secret containing the credential. It will also create a role and rolebinding so that `spec.subjects` can access secret. You can view the information in the `status` field. + +```bash +$ kubectl get secretaccessrequest gcp-cred-req -n demo -o json | jq '.status' +{ + "conditions": [ + { + "lastUpdateTime": "2019-11-12T10:40:30Z", + "message": "This was approved by kubectl vault approve secretaccessrequest", + "reason": "KubectlApprove", + "type": "Approved" + } + ], + "lease": { + "duration": "0s" + }, + "secret": { + "name": "gcp-cred-req-unyzu6" + } +} + +$ kubectl get secret -n demo gcp-cred-req-unyzu6 -o yaml +apiVersion: v1 +data: + expires_at_seconds: MTU3MzU1ODgzMA== + token: eWEyOS5jLktsMndCLTR5= + token_ttl: MzU5OQ== +kind: Secret +metadata: + name: gcp-cred-req-unyzu6 + namespace: demo +type: Opaque + +``` + +If SecretAccessRequest is deleted, then credential lease (if any) will be revoked. + +```bash +$ kubectl delete secretaccessrequest -n demo gcp-cred-req + secretaccessrequest.engine.kubevault.com "gcp-cred-req" deleted +``` + +If SecretAccessRequest is `Denied`, then the KubeVault operator will not issue any credential. + +```bash +$ kubectl vault deny secretaccessrequest gcp-cred-req -n demo + Denied +``` + +> Note: Once SecretAccessRequest is `Approved` or `Denied`, you cannot change `spec.roleRef` and `spec.subjects` field. diff --git a/content/docs/v2025.11.21/guides/secret-engines/kv/_index.md b/content/docs/v2025.11.21/guides/secret-engines/kv/_index.md new file mode 100755 index 000000000..12f973c60 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/kv/_index.md @@ -0,0 +1,17 @@ +--- +title: Key/Value | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: kv-secret-engines + name: Key/Value + parent: secret-engines-guides + weight: 20 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/secret-engines/kv/csi-driver.md b/content/docs/v2025.11.21/guides/secret-engines/kv/csi-driver.md new file mode 100644 index 000000000..6bfb0250d --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/kv/csi-driver.md @@ -0,0 +1,326 @@ +--- +title: Mount Key/Value Secrets using CSI Driver +menu: + docs_v2025.11.21: + identifier: csi-driver-kv + name: CSI Driver + parent: kv-secret-engines + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Mount Key/Value Secrets using CSI Driver + +## Kubernetes Secrets Store CSI Driver + +Secrets Store CSI driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a [Container Storage Interface (CSI)](https://kubernetes-csi.github.io/docs/) volume. + +The Secrets Store CSI driver `secrets-store.csi.k8s.io` allows Kubernetes to mount multiple secrets, keys, and certs stored in enterprise-grade external secrets stores into their pods as a volume. Once the Volume is attached, the data in it is mounted into the container’s file system. + +![Secrets-store CSI architecture](/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg) + +When the `Pod` is created through the K8s API, it’s scheduled on to a node. The `kubelet` process on the node looks at the pod spec & see if there's any `volumeMount` request. The `kubelet` issues an `RPC` to the `CSI driver` to mount the volume. The `CSI driver` creates & mounts `tmpfs` into the pod. Then the `CSI driver` issues a request to the `Provider`. The provider talks to the external secrets store to fetch the secrets & write them to the pod volume as files. At this point, volume is successfully mounted & the pod starts running. + +You can read more about the Kubernetes Secrets Store CSI Driver [here](https://secrets-store-csi-driver.sigs.k8s.io/). + +## Consuming Secrets + +At first, you need to have a Kubernetes 1.16 or later cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). To check the version of your cluster, run: + +```bash +$ kubectl version --short +Client Version: v1.21.2 +Server Version: v1.21.1 +``` + +Before you begin: + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). +- Install Secrets Store CSI driver for Kubernetes secrets in your cluster from [here](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html). +- Install Vault Specific CSI provider from [here](https://github.com/hashicorp/vault-csi-provider) + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial stored in [examples](/docs/v2025.11.21/examples/guides/secret-engines/kv) folder in GitHub repository [KubeVault/docs](https://github.com/kubevault/kubevault) + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. And we also have the service account that the Vault server can authenticate. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable and Configure KV Secret Engine + +We will use the [Vault CLI](https://www.vaultproject.io/docs/commands/#vault-commands-cli-) throughout the tutorial to [enable and configure](https://www.vaultproject.io/docs/secrets/kv/kv-v1.html#setup) the KV secret engine. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +### Enable KV Secret Engine + +Enable the KV secret engine: + +```bash +$ vault secrets enable -path=secret kv +Success! Enabled the kv secrets engine at: secret/ +``` + +### Write KV Secret + +Write arbitrary key-value pairs: + +```bash +$ vault kv put secret/db-pass password="db-secret-password" +Success! Data written to: secret/db-pass +``` + +### Read KV Secret + +Read a specific key-value pair: + +```bash +$ vault kv get secret/db-pass +====== Data ====== +Key Value +--- ----- +password db-secret-password +``` + +Let's say pod's service account name is `pod-sa` located in `demo` namespace. We need to create a [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) and a [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) so that the pod has access to read secrets from the Vault server. + +### Create Service Account for Pod + +Let's create the service account `pod-sa` which will be used in VaultPolicyBinding. +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pod-sa + namespace: demo +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/kv/serviceaccount.yaml +serviceaccount/pod-sa created + +$ kubectl get serviceaccount -n demo +NAME SECRETS AGE +pod-sa 1 4h10m +``` + +### Create VaultPolicy and VaultPolicyBinding for Pod's Service Account + +When a VaultPolicyBinding object is created, the KubeVault operator create an auth role in the Vault server. The role name is generated by the following naming format: `k8s.(clusterName or -).namespace.name`. Here, it is `k8s.-.demo.kv-se-role`. + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: kv-se-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "secret/db-pass" { + capabilities = ["read"] + } +--- +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: kv-se-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: kv-se-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "pod-sa" + serviceAccountNamespaces: + - "trial" +``` + +Let's create VaultPolicy and VaultPolicyBinding: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/kv/policy.yaml +vaultpolicy.policy.kubevault.com/kv-se-policy created + +$ kubectl apply -f docs/examples/guides/secret-engines/kv/policybinding.yaml +vaultpolicybinding.policy.kubevault.com/kv-se-role created +``` + +Check if the VaultPolicy and the VaultPolicyBinding are successfully registered to the Vault server: + +```bash +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +kv-se-policy Success 8s + +$ kubectl get vaultpolicybinding -n demo +NAME STATUS AGE +kv-se-role Success 10s +``` + +## Mount secrets into a Kubernetes pod + +So, we can create `SecretProviderClass` now. You can read more about `SecretProviderClass` [here](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#secretproviderclass). + +### Create SecretProviderClass + +Create `SecretProviderClass` object with the following content: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-database + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.kv-se-role" + objects: | + - objectName: "db-password" + secretPath: "secret/db-pass" + secretKey: "password" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/kv/secretproviderclass.yaml +secretproviderclass.secrets-store.csi.x-k8s.io/vault-database created +``` +NOTE: The `SecretProviderClass` needs to be created in the same namespace as the pod. + +### Create Pod + +Now we can create a `Pod` to consume the `KV` secrets. When the `Pod` is created, the `Provider` fetches the secret and writes them to Pod's volume as files. At this point, the volume is successfully mounted and the `Pod` starts running. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: mypod + namespace: demo +spec: + serviceAccountName: pod-sa + containers: + - image: jweissig/app:0.0.1 + name: test-app + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/test" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-database" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/kv/pod.yaml +pod/mypod created +``` +## Test & Verify + +Check if the Pod is running successfully, by running: + +```bash +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +mypod 1/1 Running 0 11s +``` + +### Verify Secret + +If the Pod is running successfully, then check inside the app container by running + +```bash +$ kubectl exec -it -n demo mypod sh +/ # ls /secrets-store/test +db-password + +/ # cat /secrets-store/test/db-password +db-secret-password + +/ # exit +``` + +So, we can see that the secret `db-password` is mounted into the pod, where the secret key is mounted as file and value is the content of that file. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted +``` diff --git a/content/docs/v2025.11.21/guides/secret-engines/kv/overview.md b/content/docs/v2025.11.21/guides/secret-engines/kv/overview.md new file mode 100644 index 000000000..ddc280d6b --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/kv/overview.md @@ -0,0 +1,352 @@ +--- +title: Manage Key/Value Secrets using the KubeVault operator +menu: + docs_v2025.11.21: + identifier: overview-kv + name: Overview + parent: kv-secret-engines + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Manage Key/Value Secrets using the KubeVault operator + +You can easily manage [KV secret engine](https://www.vaultproject.io/docs/secrets/kv/index.html#kv-secrets-engine) using the KubeVault operator. + +You should be familiar with the following CRD: + +- [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) +- [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) + +## Before you begin + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +In this tutorial, we are going to demonstrate the use of the KV secret engine. + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault + namespace: demo +spec: + clientConfig: + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1RENDQWFDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFOTVFzd0NRWURWUVFERXdKallUQWUKRncweE9URXhNVEl3T1RFMU5EQmFGdzB5T1RFeE1Ea3dPVEUxTkRCYU1BMHhDekFKQmdOVkJBTVRBbU5oTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdFZFZmtic2c2T085dnM2d1Z6bTlPQ1FYClBtYzBYTjlCWjNMbXZRTG0zdzZGaWF2aUlSS3VDVk1hN1NRSGo2L2YvOHZPeWhqNEpMcHhCM0hCYVFPZ3RrM2QKeEFDbHppU1lEd3dDbGEwSThxdklGVENLWndreXQzdHVQb0xybkppRFdTS2xJait6aFZDTHZ0enB4MDE3SEZadApmZEdhUUtlSXREUVdyNUV1QWlCMjhhSVF4WXREaVN6Y0h3OUdEMnkrblRMUEd4UXlxUlhua0d1UlIvR1B3R3lLClJ5cTQ5NmpFTmFjOE8wVERYRkIydWJQSFNza2xOU1VwSUN3S1IvR3BobnhGak1rWm4yRGJFZW9GWDE5UnhzUmcKSW94TFBhWDkrRVZxZU5jMlczN2MwQlhBSGwyMHVJUWQrVytIWDhnOVBVVXRVZW9uYnlHMDMvampvNERJRHdJRApBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFabHRFN0M3a3ZCeTNzeldHY0J0SkpBTHZXY3ZFeUdxYUdCYmFUbGlVbWJHTW9QWXoKbnVqMUVrY1I1Qlg2YnkxZk15M0ZtZkJXL2E0NU9HcDU3U0RMWTVuc2w0S1RlUDdGZkFYZFBNZGxrV0lQZGpnNAptOVlyOUxnTThkOGVrWUJmN0paUkNzcEorYkpDU1A2a2p1V3l6MUtlYzBOdCtIU0psaTF3dXIrMWVyMUprRUdWClBQMzFoeTQ2RTJKeFlvbnRQc0d5akxlQ1NhTlk0UWdWK3ZneWJmSlFEMVYxbDZ4UlVlMzk2YkJ3aS94VGkzN0oKNWxTVklmb1kxcUlBaGJPbjBUWHp2YzBRRXBKUExaRDM2VDBZcEtJSVhjZUVGYXNxZzVWb1pINGx1Uk50SStBUAp0blg4S1JZU0xGOWlCNEJXd0N0aGFhZzZFZVFqYWpQNWlxZnZoUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + service: + name: vault + port: 8200 + scheme: HTTPS + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: kubernetes + vaultRole: vault-policy-controller + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true +``` + +## Use KV Secret Engine as Root User + +Here, we are going to use the Vault root token to perform authentication to the Vault server. We will use the [Vault CLI](https://www.vaultproject.io/docs/commands/#vault-commands-cli-) throughout the tutorial. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +Export the root token as environment variable: + +```bash +export VAULT_TOKEN=s.lbSCc2GGit1QmqghBgYgjbOG +``` + +### Enable KV Secret Engine + +Enable the KV secret engine: + +```bash +$ vault secrets enable -version=1 kv +Success! Enabled the kv secrets engine at: kv/ +``` + +### Write KV Secrets + +Write arbitrary key-value pairs: + +```bash +$ vault kv put kv/my-secret my-value=s3cr3t +Success! Data written to: kv/my-secret + +$ vault kv put kv/secret-name secret-value=8HI.HFDJK324 +Success! Data written to: kv/secret-name + +$ vault kv put kv/key value=sdfkjdslkfjdslj +Success! Data written to: kv/key +``` + +### List KV Secrets + +List key-value pairs: + +```bash +$ vault kv list kv/ +Keys +---- +key +my-secret +secret-name +``` + +### Read KV Secret + +Read a specific key-value pair: + +```bash +$ vault kv get kv/my-secret +====== Data ====== +Key Value +--- ----- +my-value s3cr3t +``` + +### Delete KV Secrets + +Delete a specific key-value pair: + +```bash +$ vault kv delete kv/my-secret +Success! Data deleted (if it existed) at: kv/my-secret +``` + +## Use KV Secret Engine as Non-root User + +Here, we are going to create a Kubernetes service account and give it limited access (i.e only KV secret engine) from the Vault using the VaultPolicy and the VaultPolicyBinding. + +### Create Kubernetes Service Account + +Create a service account `kv-admin` to the `demo` namespace: + +```bash +$ kubectl create serviceaccount -n demo kv-admin +serviceaccount/kv-admin created + +# get service account JWT token which will be required while performing +# login operation to the Vault +$ kubectl get secret -n demo kv-admin-token-8cgr2 -o jsonpath="{.data.token}" | base64 -d +eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZW1vIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Imt2LWFkbWluLXRva2VuLThjZ3IyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6Imt2LWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMjhiNDdlMWQtMzQyZC00MjYyLWI0NDItMzRjYzViOTFhYThlIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlbW86a3YtYWRtaW4ifQ.NkAbcuOsziZCtDtUYuxzuCKcAVuywnIbdEHylB1un6yc5K_Qfl_AtsnuKjWbJDZtp1kjc6bwy6dftMPSoPwd6U9FO5kbGbLqoA6vsa3Y_gJ74dhYqZnGHZZg9KpCxLHxvl8phcjIrRMvKW_dn95p334GWSI_AqU1zvGTQnFhjlrb-NRKpeTA7N7Y1JP2x1wB8KdtHha-qqGmLsUMJbc8VebgKnG8zjhc1KfgtO0lMLt4uLthBS4ca10r4fOsz259n66FOkVPfbPnXlUYzeObz-Ng4cFwdZ6xLgdF2wz9e8pTKXhe8NifzTFMk_44TPpE5pBqsog80lfMuq7Tk4O3TQ +``` + +### Create VaultPolicy and VaultPolicyBinding + +A sample VaultPolicy object with necessary path permission for KV secret engine: + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: kv-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "sys/mounts" { + capabilities = ["read", "list"] + } + + path "sys/mounts/*" { + capabilities = ["create", "read", "update", "delete"] + } + + path "kv/*" { + capabilities = ["create","list", "read", "update", "delete"] + } + + path "sys/leases/revoke/*" { + capabilities = ["update"] + } +``` + +Create VaultPolicy and check status: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/kv/policy.yaml +vaultpolicy.policy.kubevault.com/kv-policy created + +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +kv-policy Success 8m51s +``` + +A sample VaultPolicyBinding object that binds the `kv-policy` to the `kv-admin` service account: + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: kv-admin-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: kv-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "kv-admin" + serviceAccountNamespaces: + - "demo" + ttl: "1000" + maxTTL: "2000" + period: "1000" +``` + +Create VaultPolicyBinding and check status: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/kv/policyBinding.yaml +vaultpolicybinding.policy.kubevault.com/kv-admin-role created + +$ kubectl get vaultpolicybindings -n demo +NAME STATUS AGE +kv-admin-role Success 4m56s +``` + +### Login Vault and Use KV Secret Engine + +To resolve the naming conflict, name of the policy and role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +List Vault policies and Kubernetes auth roles: + +```bash +$ vault list sys/policy +Keys +---- +k8s.-.demo.kv-policy +k8s.-.demo.vault-auth-method-controller +vault-policy-controller + +$ vault list auth/kubernetes/role +Keys +---- +k8s.-.demo.kv-admin-role +k8s.-.demo.vault-auth-method-controller +vault-policy-controller + +$ vault read auth/kubernetes/role/k8s.-.demo.kv-admin-role +Key Value +--- ----- +bound_service_account_names [kv-admin] +bound_service_account_namespaces [demo] +max_ttl 33m20s +period 16m40s +policies [k8s.-.demo.kv-policy] +token_bound_cidrs [] +token_explicit_max_ttl 0s +token_max_ttl 33m20s +token_no_default_policy false +token_num_uses 0 +token_period 16m40s +token_policies [k8s.-.demo.kv-policy] +token_ttl 16m40s +token_type default +ttl 16m40s +``` + +So, we can see that the `kv-policy` is added to the `kv-admin-role`. + +Now, login to the Vault using `kv-admin`'s JWT token under `kv-admin-role` role. + +```bash +$ vault write auth/kubernetes/login \ + role=k8s.-.demo.kv-admin-role \ + jwt=eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZW1vIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Imt2LWFkbWluLXRva2VuLThjZ3IyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6Imt2LWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMjhiNDdlMWQtMzQyZC00MjYyLWI0NDItMzRjYzViOTFhYThlIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlbW86a3YtYWRtaW4ifQ.NkAbcuOsziZCtDtUYuxzuCKcAVuywnIbdEHylB1un6yc5K_Qfl_AtsnuKjWbJDZtp1kjc6bwy6dftMPSoPwd6U9FO5kbGbLqoA6vsa3Y_gJ74dhYqZnGHZZg9KpCxLHxvl8phcjIrRMvKW_dn95p334GWSI_AqU1zvGTQnFhjlrb-NRKpeTA7N7Y1JP2x1wB8KdtHha-qqGmLsUMJbc8VebgKnG8zjhc1KfgtO0lMLt4uLthBS4ca10r4fOsz259n66FOkVPfbPnXlUYzeObz-Ng4cFwdZ6xLgdF2wz9e8pTKXhe8NifzTFMk_44TPpE5pBqsog80lfMuq7Tk4O3TQ +Key Value +--- ----- +token s.HJ8owGJLrqzlnA8tKuYdrElh +token_accessor FHN3pCvTAoyZuq7FZoOe1fSc +token_duration 16m40s +token_renewable true +token_policies ["default" "k8s.-.demo.kv-policy"] +identity_policies [] +policies ["default" "k8s.-.demo.kv-policy"] +token_meta_role k8s.-.demo.kv-admin-role +token_meta_service_account_name kv-admin +token_meta_service_account_namespace demo +token_meta_service_account_secret_name kv-admin-token-8cgr2 +token_meta_service_account_uid 28b47e1d-342d-4262-b442-34cc5b91aa8e +``` + +Export the new Vault token as an environment variable: + +```bash +export VAULT_TOKEN=s.HJ8owGJLrqzlnA8tKuYdrElh +``` + +Now perform read, write, list and delete operation on KV secret engine: + +```bash +# Enable KV secret engine +$ vault secrets enable -version=1 kv +Success! Enabled the kv secrets engine at: kv/ + +# Write KV secret +$ vault kv put kv/my-secret my-value=s3cr3t +Success! Data written to: kv/my-secret + +# List KV secrets +$ vault kv list kv/ +Keys +---- +my-secret + +# Read KV secret +$ vault kv get kv/my-secret +====== Data ====== +Key Value +--- ----- +my-value s3cr3t + +# Delete KV secret +$ vault kv delete kv/my-secret +Success! Data deleted (if it existed) at: kv/my-secret +``` + +To learn more usages of Vault `Key/Vaule` secret engine click [this](https://www.vaultproject.io/docs/secrets/kv/kv-v1.html#usage). \ No newline at end of file diff --git a/content/docs/v2025.11.21/guides/secret-engines/mariadb/_index.md b/content/docs/v2025.11.21/guides/secret-engines/mariadb/_index.md new file mode 100644 index 000000000..18775d0f5 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/mariadb/_index.md @@ -0,0 +1,17 @@ +--- +title: MariaDB | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: mariadb-secret-engines + name: MariaDB + parent: secret-engines-guides + weight: 40 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/secret-engines/mariadb/csi-driver.md b/content/docs/v2025.11.21/guides/secret-engines/mariadb/csi-driver.md new file mode 100644 index 000000000..a4e11a402 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/mariadb/csi-driver.md @@ -0,0 +1,297 @@ +--- +title: Mount MariaDB Secrets using CSI Driver +menu: + docs_v2025.11.21: + identifier: csi-driver-mariadb + name: CSI Driver + parent: mariadb-secret-engines + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Mount MariaDB Secrets using CSI Driver + +## Kubernetes Secrets Store CSI Driver + +Secrets Store CSI driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a [Container Storage Interface (CSI)](https://kubernetes-csi.github.io/docs/) volume. + +The Secrets Store CSI driver `secrets-store.csi.k8s.io` allows Kubernetes to mount multiple secrets, keys, and certs stored in enterprise-grade external secrets stores into their pods as a volume. Once the Volume is attached, the data in it is mounted into the container’s file system. + +![Secrets-store CSI architecture](/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg) + +When the `Pod` is created through the K8s API, it’s scheduled on to a node. The `kubelet` process on the node looks at the pod spec & see if there's any `volumeMount` request. The `kubelet` issues an `RPC` to the `CSI driver` to mount the volume. The `CSI driver` creates & mounts `tmpfs` into the pod. Then the `CSI driver` issues a request to the `Provider`. The provider talks to the external secrets store to fetch the secrets & write them to the pod volume as files. At this point, volume is successfully mounted & the pod starts running. + +You can read more about the Kubernetes Secrets Store CSI Driver [here](https://secrets-store-csi-driver.sigs.k8s.io/). + +## Consuming Secrets + +At first, you need to have a Kubernetes 1.16 or later cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). To check the version of your cluster, run: + +```bash +$ kubectl version --short +Client Version: v1.21.2 +Server Version: v1.21.1 +``` + +Before you begin: + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). +- Install Secrets Store CSI driver for Kubernetes secrets in your cluster from [here](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html). +- Install Vault Specific CSI provider from [here](https://github.com/hashicorp/vault-csi-provider) + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial stored in [examples](/docs/v2025.11.21/examples/guides/secret-engines/mariadb) folder in GitHub repository [KubeVault/docs](https://github.com/kubevault/kubevault) + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. And we also have the service account that the Vault server can authenticate. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable & Configure MariaDB SecretEngine + +### Enable MariaDB SecretEngine + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mariadb/secretengine.yaml +secretengine.engine.kubevault.com/mariadb-engine created +``` + +### Create MariaDBRole + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mariadb/secretenginerole.yaml +mariadbrole.engine.kubevault.com/mariadb-superuser-role created +``` + +Let's say pod's service account name is `test-user-account` located in `demo` namespace. We need to create a [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) and a [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) so that the pod has access to read secrets from the Vault server. + +### Create Service Account for Pod + +Let's create the service account `test-user-account` which will be used in VaultPolicyBinding. +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mariadb/serviceaccount.yaml +serviceaccount/test-user-account created + +$ kubectl get serviceaccount -n demo +NAME SECRETS AGE +test-user-account 1 4h10m +``` + +### Create SecretRoleBinding for Pod's Service Account + +SecretRoleBinding will create VaultPolicy and VaultPolicyBinding inside vault. +When a VaultPolicyBinding object is created, the KubeVault operator create an auth role in the Vault server. The role name is generated by the following naming format: `k8s.(clusterName or -).namespace.name`. Here, it is `k8s.kubevault.com.demo.postgres-superuser-role`. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: MariaDBRole + name: mariadb-superuser-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo +``` + +Let's create SecretRoleBinding: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mariadb/secret-role-binding.yaml +secretrolebinding.engine.kubevault.com/secret-role-binding created +``` +Check if the VaultPolicy and the VaultPolicyBinding are successfully registered to the Vault server: + +```bash +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 8s + +$ kubectl get vaultpolicybinding -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 10s +``` + +## Mount secrets into a Kubernetes pod + +So, we can create `SecretProviderClass` now. You can read more about `SecretProviderClass` [here](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#secretproviderclass). + +### Create SecretProviderClass + +Create `SecretProviderClass` object with the following content: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.mariadb-reader-role" + objects: | + - objectName: "mariadb-creds-username" + secretPath: "your-database-path/creds/k8s.-.demo.mariadb-superuser-role" + secretKey: "username" + - objectName: "mariadb-creds-password" + secretPath: "your-database-path/creds/k8s.-.demo.mariadb-superuser-role" + secretKey: "password" + +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mariadb/secretproviderclass.yaml +secretproviderclass.secrets-store.csi.x-k8s.io/vault-db-provider created +``` + +NOTE: The `SecretProviderClass` needs to be created in the same namespace as the pod. + +### Create Pod + +Now we can create a `Pod` to consume the `MariaDB` secrets. When the `Pod` is created, the `Provider` fetches the secret and writes them to Pod's volume as files. At this point, the volume is successfully mounted and the `Pod` starts running. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/mariadb-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mariadb/pod.yaml +pod/demo-app created +``` +## Test & Verify + +Check if the Pod is running successfully, by running: + +```bash +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +demo-app 1/1 Running 0 11s +``` + +### Verify Secret + +If the Pod is running successfully, then check inside the app container by running + +```bash +$ kubectl exec -it -n demo pod/demo-app -- /bin/sh +/ # ls /secrets-store/mariadb-creds +mariadb-creds-password mariadb-creds-username + +/ # cat /secrets-store/mariadb-creds/mariadb-creds-password +TAu2Zvg1WYE07W8Uf-nW + +/ # cat /secrets-store/mariadb-creds/mariadb-creds-username +v-kubernetes-test-k8s.-.demo.mariadb-s-iPkxiH80Ollq2QgF82Ab-1629178048 + +/ # exit +``` + +So, we can see that the secret `db-username` and `db-password` is mounted into the pod, where the secret key is mounted as file and value is the content of that file. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted + +``` diff --git a/content/docs/v2025.11.21/guides/secret-engines/mariadb/overview.md b/content/docs/v2025.11.21/guides/secret-engines/mariadb/overview.md new file mode 100644 index 000000000..434c9a09c --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/mariadb/overview.md @@ -0,0 +1,337 @@ +--- +title: Manage MariaDB credentials using the KubeVault operator +menu: + docs_v2025.11.21: + identifier: overview-mariadb + name: Overview + parent: mariadb-secret-engines + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Manage MariaDB credentials using the KubeVault operator + +MariaDB is one of the supported plugins for the database secrets engine. This plugin generates database credentials dynamically based on configured roles for the MariaDB database. You can easily manage [MariaDB secret engine](https://www.vaultproject.io/docs/secrets/databases/mysql-maria.html) using the KubeVault operator. + +![MariaDB secret engine](/docs/v2025.11.21/images/guides/secret-engines/mariadb/mariadb_secret_engine_guide.svg) + +You need to be familiar with the following CRDs: + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) +- [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) +- [MariaDBRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mariadb) + +## Before you begin + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +In this tutorial, we are going to create a [role](https://www.vaultproject.io/docs/secrets/databases/mysql-maria#setup) using MariaDB and issue credential using SecretAccessRequest. + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable and Configure MariaDB Secret Engine + +When a [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) crd object is created, the KubeVault operator will enable a secret engine on specified path and configure the secret engine with given configurations. + +A sample SecretEngine object for the MariaDB secret engine: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: mariadb-engine + namespace: demo +spec: + vaultRef: + name: vault + mariadb: + databaseRef: + name: mariadb + namespace: demo + pluginName: "mysql-database-plugin" +``` + +Let's deploy SecretEngine: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mariadb/secretengine.yaml +secretengine.engine.kubevault.com/mariadb-engine created +``` + +Wait till the status become `Success`: + +```bash +$ kubectl get secretengines -n demo +NAME STATUS AGE +mariadb-engine Success 10s +``` + +Since the status is `Success`, the MariaDB secret engine is enabled and successfully configured. You can use `kubectl describe secretengine -n ` to check for error events, if any. + +## Create MariaDB Role + +By using [MariaDBRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mariadb), you can create a [role](https://www.vaultproject.io/docs/secrets/databases/mysql-maria#setup) on the Vault server in Kubernetes native way. + +A sample MariaDBRole object is given below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: MariaDBRole +metadata: + name: mariadb-superuser-role + namespace: demo +spec: + secretEngineRef: + name: sql-secrt-engine + creationStatements: + - "CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';" + - "GRANT SELECT ON *.* TO '{{name}}'@'%';" + defaultTTL: 1h + maxTTL: 24h +``` + +Let's deploy MariaDBRole: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mariadb/secretenginerole.yaml +mariadbrole.engine.kubevault.com/mariadb-superuser-role created + +$ kubectl get mariadbrole -n demo +NAME STATUS AGE +mariadb-superuser-role Success 34m +``` + +You can also check from Vault that the role is created. +To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +```bash +$ vault list your-database-path/roles +Keys +---- +k8s.-.demo.mariadb-superuser-role + +$ vault read your-database-path/roles/k8s.-.demo.mariadb-superuser-role +Key Value +--- ----- +creation_statements [CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; GRANT SELECT ON *.* TO '{{name}}'@'%';] +db_name k8s.-.demo.mariadb +default_ttl 1h +max_ttl 24h +renew_statements [] +revocation_statements [] +rollback_statements [] +``` + +If we delete the MariaDB, then the respective role will be deleted from the Vault. + +```bash +$ kubectl delete mariadbrole -n demo mariadb-superuser-role +mariadbrole.engine.kubevault.com "mariadb-superuser-role" deleted +``` + +Check from Vault whether the role exists: + +```bash +$ vault read your-database-path/roles/k8s.-.demo.mariadb-superuser-role +No value found at your-database-path/roles/k8s.-.demo.mariadb-superuser-role + +$ vault list your-database-path/roles +No value found at your-database-path/roles/ +``` + +## Generate MariaDB credentials + +Here, we are going to make a request to Vault for MariaDB credentials by creating `mariadb-cred-rqst` SecretAccessRequest in `demo` namespace. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: mariadb-cred-rqst + namespace: demo +spec: + roleRef: + kind: MariaDBRole + name: mariadb-superuser-role + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +``` + +Here, `spec.roleRef` is the reference of MariaDB against which credentials will be issued. `spec.subjects` is the reference to the object or user identities a role binding applies to it will have read access of the credential secret. + +Now, we are going to create SecretAccessRequest. + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mariadb/mariadbaccessrequest.yaml +secretaccessrequest.engine.kubevault.com/mariadb-cred-rqst created + +$ kubectl get secretaccessrequest -n demo +NAME AGE +mariadb-cred-rqst 72m +``` + +Database credentials will not be issued until it is approved. The KubeVault operator will watch for the approval in the `status.conditions[].type` field of the request object. You can use [KubeVault CLI](https://github.com/kubevault/cli), a [kubectl plugin](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/), to approve or deny SecretAccessRequest. + +```bash +# using KubeVault CLI as kubectl plugin to approve request +$ kubectl vault approve secretaccessrequest mariadb-cred-rqst -n demo +approved + +$ kubectl get secretaccessrequest -n demo mariadb-cred-rqst -o yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: mariadb-cred-rqst + namespace: demo +spec: + roleRef: + kind: MariaDBRole + name: mariadb-superuser-role + namespace: demo + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +status: + conditions: + - lastUpdateTime: "2020-11-18T06:41:57Z" + message: This was approved by kubectl vault approve secretaccessrequest + reason: KubectlApprove + type: Approved + lease: + duration: 1h0m0s + id: your-database-path/creds/k8s.-.demo.mariadb-superuser-role/ni3TCo2HkSwCUb8kmQuvIDdx + renewable: true + secret: + name: mariadb-cred-rqst-gy66wq +``` + +Once SecretAccessRequest is approved, the KubeVault operator will issue credentials from Vault and create a secret containing the credential. It will also create a role and rolebinding so that `spec.subjects` can access secret. You can view the information in the `status` field. + +```bash +$ kubectl get secretaccessrequest mariadb-cred-rqst -n demo -o json | jq '.status' +{ + "conditions": [ + { + "lastUpdateTime": "2019-11-18T06:41:57Z", + "message": "This was approved by kubectl vault approve secretaccessrequest", + "reason": "KubectlApprove", + "type": "Approved" + } + ], + "lease": { + "duration": "1h0m0s", + "id": "your-database-path/creds/k8s.-.demo.mariadb-superuser-role/ni3TCo2HkSwCUb8kmQuvIDdx", + "renewable": true + }, + "secret": { + "name": "mariadb-cred-rqst-gy66wq" + } +} + +$ kubectl get secret -n demo mariadb-cred-rqst-gy66wq -o yaml +apiVersion: v1 +data: + password: QTFhLVBkZGlsZFFxa0o1cnlvR20= + username: di1rdWJlcm5ldGVzLWRlbW8TE1NzQwNTkzMTc= +kind: Secret +metadata: + name: mariadb-cred-rqst-gy66wq + namespace: demo + ownerReferences: + - apiVersion: engine.kubevault.com/v1alpha1 + controller: true + kind: SecretAccessRequest + name: mariadb-cred-rqst + uid: 54ce63ca-d0e7-4b97-9085-b52eb3cb334f +type: Opaque +``` + +If SecretAccessRequest is deleted, then credential lease (if any) will be revoked. + +```bash +$ kubectl delete secretaccessrequest -n demo mariadb-cred-rqst +secretaccessrequest.engine.kubevault.com "mariadb-cred-rqst" deleted +``` + +If SecretAccessRequest is `Denied`, then the KubeVault operator will not issue any credential. + +```bash +$ kubectl vault deny secretaccessrequest mariadb-cred-rqst -n demo + Denied +``` + +> Note: Once SecretAccessRequest is `Approved`, you cannot change `spec.roleRef` and `spec.subjects` field. diff --git a/content/docs/v2025.11.21/guides/secret-engines/mongodb/_index.md b/content/docs/v2025.11.21/guides/secret-engines/mongodb/_index.md new file mode 100755 index 000000000..d482f96f1 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/mongodb/_index.md @@ -0,0 +1,17 @@ +--- +title: MongoDB | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: mongodb-secret-engines + name: MongoDB + parent: secret-engines-guides + weight: 30 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/secret-engines/mongodb/csi-driver.md b/content/docs/v2025.11.21/guides/secret-engines/mongodb/csi-driver.md new file mode 100644 index 000000000..f7d0f520f --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/mongodb/csi-driver.md @@ -0,0 +1,295 @@ +--- +title: Mount MongoDB Secrets using CSI Driver +menu: + docs_v2025.11.21: + identifier: csi-driver-mongodb + name: CSI Driver + parent: mongodb-secret-engines + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Mount MongoDB Secrets using CSI Driver + +## Kubernetes Secrets Store CSI Driver + +Secrets Store CSI driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a [Container Storage Interface (CSI)](https://kubernetes-csi.github.io/docs/) volume. + +The Secrets Store CSI driver `secrets-store.csi.k8s.io` allows Kubernetes to mount multiple secrets, keys, and certs stored in enterprise-grade external secrets stores into their pods as a volume. Once the Volume is attached, the data in it is mounted into the container’s file system. + +![Secrets-store CSI architecture](/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg) + +When the `Pod` is created through the K8s API, it’s scheduled on to a node. The `kubelet` process on the node looks at the pod spec & see if there's any `volumeMount` request. The `kubelet` issues an `RPC` to the `CSI driver` to mount the volume. The `CSI driver` creates & mounts `tmpfs` into the pod. Then the `CSI driver` issues a request to the `Provider`. The provider talks to the external secrets store to fetch the secrets & write them to the pod volume as files. At this point, volume is successfully mounted & the pod starts running. + +You can read more about the Kubernetes Secrets Store CSI Driver [here](https://secrets-store-csi-driver.sigs.k8s.io/). + +## Consuming Secrets + +At first, you need to have a Kubernetes 1.16 or later cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). To check the version of your cluster, run: + +```bash +$ kubectl version --short +Client Version: v1.21.2 +Server Version: v1.21.1 +``` + +Before you begin: + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). +- Install Secrets Store CSI driver for Kubernetes secrets in your cluster from [here](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html). +- Install Vault Specific CSI provider from [here](https://github.com/hashicorp/vault-csi-provider) + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial stored in [examples](/docs/v2025.11.21/examples/guides/secret-engines/mongodb) folder in GitHub repository [KubeVault/docs](https://github.com/kubevault/kubevault) + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. And we also have the service account that the Vault server can authenticate. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable & Configure MongoDB SecretEngine + +### Enable MongoDB SecretEngine + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mongodb/secretengine.yaml +secretengine.engine.kubevault.com/mongo-engine created +``` + +### Create MongoDBRole + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mongodb/secretenginerole.yaml +mongodbroles.engine.kubevault.com/mongo-superuser-role created +``` + +Let's say pod's service account name is `test-user-account` located in `demo` namespace. We need to create a [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) and a [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) so that the pod has access to read secrets from the Vault server. + +### Create Service Account for Pod + +Let's create the service account `test-user-account` which will be used in VaultPolicyBinding. +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mongodb/serviceaccount.yaml +serviceaccount/test-user-account created + +$ kubectl get serviceaccount -n demo +NAME SECRETS AGE +test-user-account 1 4h10m +``` + +### Create SecretRoleBinding for Pod's Service Account + +SecretRoleBinding will create VaultPolicy and VaultPolicyBinding inside vault. +When a VaultPolicyBinding object is created, the KubeVault operator create an auth role in the Vault server. The role name is generated by the following naming format: `k8s.(clusterName or -).namespace.name`. Here, it is `k8s.kubevault.com.demo.postgres-superuser-role`. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: MongoDBRole + name: mongo-superuser-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo +``` + +Let's create SecretRoleBinding: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mongodb/secretrolebinding.yaml +secretrolebinding.engine.kubevault.com/secret-role-binding created +``` +Check if the VaultPolicy and the VaultPolicyBinding are successfully registered to the Vault server: + +```bash +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 8s + +$ kubectl get vaultpolicybinding -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 10s +``` + +## Mount secrets into a Kubernetes pod + +So, we can create `SecretProviderClass` now. You can read more about `SecretProviderClass` [here](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#secretproviderclass). + +### Create SecretProviderClass + +Create `SecretProviderClass` object with the following content: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.mongo-reader-role" + objects: | + - objectName: "mongo-creds-username" + secretPath: "your-database-path/creds/k8s.-.demo.mongo-superuser-role" + secretKey: "username" + - objectName: "mongo-creds-password" + secretPath: "your-database-path/creds/k8s.-.demo.mongo-superuser-role" + secretKey: "password" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mongodb/secretproviderclass.yaml +secretproviderclass.secrets-store.csi.x-k8s.io/vault-db-provider created +``` + +NOTE: The `SecretProviderClass` needs to be created in the same namespace as the pod. + +### Create Pod + +Now we can create a `Pod` to consume the `MongoDB` secrets. When the `Pod` is created, the `Provider` fetches the secret and writes them to Pod's volume as files. At this point, the volume is successfully mounted and the `Pod` starts running. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/mongo-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mongodb/pod.yaml +pod/demo-app created +``` +## Test & Verify + +Check if the Pod is running successfully, by running: + +```bash +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +demo-app 1/1 Running 0 11s +``` + +### Verify Secret + +If the Pod is running successfully, then check inside the app container by running + +```bash +$ kubectl exec -it -n demo pod/demo-app -- /bin/sh +/ # ls /secrets-store/mongo-creds +mongo-creds-password mongo-creds-username + +/ # cat /secrets-store/mongo-creds/mongo-creds-password +TAu2Zvg1WYE07W8Uf-nW + +/ # cat /secrets-store/mongo-creds/mongo-creds-username +v-kubernetes-test-k8s.-.demo.mongo-s-iPkxiH80Ollq2QgF82Ab-1629178048 + +/ # exit +``` + +So, we can see that the secret `db-username` and `db-password` is mounted into the pod, where the secret key is mounted as file and value is the content of that file. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted +``` diff --git a/content/docs/v2025.11.21/guides/secret-engines/mongodb/overview.md b/content/docs/v2025.11.21/guides/secret-engines/mongodb/overview.md new file mode 100644 index 000000000..4d3622e32 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/mongodb/overview.md @@ -0,0 +1,336 @@ +--- +title: Manage MongoDB credentials using the KubeVault operator +menu: + docs_v2025.11.21: + identifier: overview-mongodb + name: Overview + parent: mongodb-secret-engines + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Manage MongoDB credentials using the KubeVault operator + +MongoDB is one of the supported plugins for the database secrets engine. This plugin generates database credentials dynamically based on configured roles for the MongoDB database. You can easily manage [MongoDB secret engine](https://www.vaultproject.io/docs/secrets/databases/mongodb.html) using the KubeVault operator. + +![MongoDB secret engine](/docs/v2025.11.21/images/guides/secret-engines/mongodb/mongodb_secret_engine_guide.svg) + +You need to be familiar with the following CRDs: + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) +- [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) +- [MongoDBRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mongodb) + +## Before you begin + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +In this tutorial, we are going to create a [role](https://www.vaultproject.io/docs/secrets/databases/mongodb#setup) using MongoDB and issue credential using SecretAccessRequest. + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable and Configure MongoDB Secret Engine + +When a [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) crd object is created, the KubeVault operator will enable a secret engine on specified path and configure the secret engine with given configurations. + +A sample SecretEngine object for the MongoDB secret engine: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: mongo-engine + namespace: demo +spec: + vaultRef: + name: vault + mongodb: + databaseRef: + name: mongodb + namespace: demo + pluginName: "mongodb-database-plugin" +``` + +Let's deploy SecretEngine: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mongodb/secretengine.yaml +secretengine.engine.kubevault.com/mongo-engine created +``` + +Wait till the status become `Success`: + +```bash +$ kubectl get secretengines -n demo +NAME STATUS AGE +mongo-engine Success 10s +``` + +Since the status is `Success`, the MongoDB secret engine is enabled and successfully configured. You can use `kubectl describe secretengine -n ` to check for error events, if any. + +## Create MongoDB Role + +By using [MongoDBRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mongodb), you can create a [role](https://www.vaultproject.io/docs/secrets/databases/mongodb#setup) on the Vault server in Kubernetes native way. + +A sample MongoDBRole object is given below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: MongoDBRole +metadata: + name: mongo-superuser-role + namespace: demo +spec: + secretEngineRef: + name: mongo-secret-engine + creationStatements: + - "{ \"db\": \"admin\", \"roles\": [{ \"role\": \"readWrite\" }, {\"role\": \"read\", \"db\": \"foo\"}] }" + defaultTTL: 1h + maxTTL: 24h +``` + +Let's deploy MongoDBRole: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mongodb/secretenginerole.yaml +mongodbrole.engine.kubevault.com/mongo-superuser-role created + +$ kubectl get mongodbrole -n demo +NAME STATUS AGE +mongo-superuser-role Success 34m +``` + +You can also check from Vault that the role is created. +To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +```bash +$ vault list your-database-path/roles +Keys +---- +k8s.-.demo.mongo-superuser-role + +$ vault read your-database-path/roles/k8s.-.demo.mongo-superuser-role +Key Value +--- ----- +creation_statements [{ "db": "admin", "roles": [{ "role": "readWrite" }, {"role": "read", "db": "foo"}] }] +db_name k8s.-.db.mongodb +default_ttl 1h +max_ttl 24h +renew_statements [] +revocation_statements [] +rollback_statements [] +``` + +If we delete the MongoDBRole, then the respective role will be deleted from the Vault. + +```bash +$ kubectl delete mongodbrole -n demo mongo-superuser-role +mongodbrole.engine.kubevault.com "mongo-superuser-role" deleted +``` + +Check from Vault whether the role exists: + +```bash +$ vault read your-database-path/roles/k8s.-.demo.mongo-superuser-role +No value found at your-database-path/roles/k8s.-.demo.mongo-superuser-role + +$ vault list your-database-path/roles +No value found at your-database-path/roles/ +``` + +## Generate MongoDB credentials + +Here, we are going to make a request to Vault for MongoDB credentials by creating `mongo-cred-rqst` SecretAccessRequest in `demo` namespace. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: mongo-cred-rqst + namespace: demo +spec: + roleRef: + kind: MongoDBRole + name: mongo-superuser-role + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +``` + +Here, `spec.roleRef` is the reference of MongoDB against which credentials will be issued. `spec.subjects` is the reference to the object or user identities a role binding applies to it will have read access of the credential secret. + +Now, we are going to create SecretAccessRequest. + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mongodb/mongodbaccessrequest.yaml +secretaccessrequest.engine.kubevault.com/mongo-cred-rqst created + +$ kubectl get secretaccessrequest -n demo +NAME AGE +mongo-cred-rqst 72m +``` + +Database credentials will not be issued until it is approved. The KubeVault operator will watch for the approval in the `status.conditions[].type` field of the request object. You can use [KubeVault CLI](https://github.com/kubevault/cli), a [kubectl plugin](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/), to approve or deny SecretAccessRequest. + +```bash +# using KubeVault CLI as kubectl plugin to approve request +$ kubectl vault approve secretaccessrequest mongo-cred-rqst -n demo +approved + +$ kubectl get secretaccessrequest -n demo mongo-cred-rqst -o yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: mongo-cred-rqst + namespace: demo +spec: + roleRef: + kind: MongoDBRole + name: mongo-superuser-role + namespace: demo + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +status: + conditions: + - lastUpdateTime: "2020-11-18T06:41:57Z" + message: This was approved by kubectl vault approve secretaccessrequest + reason: KubectlApprove + type: Approved + lease: + duration: 1h0m0s + id: your-database-path/creds/k8s.-.demo.mongo-superuser-role/ni3TCo2HkSwCUb8kmQuvIDdx + renewable: true + secret: + name: mongo-cred-rqst-gy66wq +``` + +Once SecretAccessRequest is approved, the KubeVault operator will issue credentials from Vault and create a secret containing the credential. It will also create a role and rolebinding so that `spec.subjects` can access secret. You can view the information in the `status` field. + +```bash +$ kubectl get secretaccessrequest mongo-cred-rqst -n demo -o json | jq '.status' +{ + "conditions": [ + { + "lastUpdateTime": "2019-11-18T06:41:57Z", + "message": "This was approved by kubectl vault approve secretaccessrequest", + "reason": "KubectlApprove", + "type": "Approved" + } + ], + "lease": { + "duration": "1h0m0s", + "id": "your-database-path/creds/k8s.-.demo.mongo-superuser-role/ni3TCo2HkSwCUb8kmQuvIDdx", + "renewable": true + }, + "secret": { + "name": "mongo-cred-rqst-gy66wq" + } +} + +$ kubectl get secret -n demo mongo-cred-rqst-gy66wq -o yaml +apiVersion: v1 +data: + password: QTFhLVBkZGlsZFFxa0o1cnlvR20= + username: di1rdWJlcm5ldGVzLWRlbW8TE1NzQwNTkzMTc= +kind: Secret +metadata: + name: mongo-cred-rqst-gy66wq + namespace: demo + ownerReferences: + - apiVersion: engine.kubevault.com/v1alpha1 + controller: true + kind: SecretAccessRequest + name: mongo-cred-rqst + uid: 54ce63ca-d0e7-4b97-9085-b52eb3cb334f +type: Opaque +``` + +If SecretAccessRequest is deleted, then credential lease (if any) will be revoked. + +```bash +$ kubectl delete secretaccessrequest -n demo mongo-cred-rqst +secretaccessrequest.engine.kubevault.com "mongo-cred-rqst" deleted +``` + +If SecretAccessRequest is `Denied`, then the KubeVault operator will not issue any credential. + +```bash +$ kubectl vault deny secretaccessrequest mongo-cred-rqst -n demo + Denied +``` + +> Note: Once SecretAccessRequest is `Approved`, you cannot change `spec.roleRef` and `spec.subjects` field. diff --git a/content/docs/v2025.11.21/guides/secret-engines/mysql/_index.md b/content/docs/v2025.11.21/guides/secret-engines/mysql/_index.md new file mode 100755 index 000000000..e10552c7e --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/mysql/_index.md @@ -0,0 +1,17 @@ +--- +title: MySQL | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: mysql-secret-engines + name: MySQL + parent: secret-engines-guides + weight: 40 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/secret-engines/mysql/csi-driver.md b/content/docs/v2025.11.21/guides/secret-engines/mysql/csi-driver.md new file mode 100644 index 000000000..36fc00790 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/mysql/csi-driver.md @@ -0,0 +1,297 @@ +--- +title: Mount MySQL Secrets using CSI Driver +menu: + docs_v2025.11.21: + identifier: csi-driver-mysql + name: CSI Driver + parent: mysql-secret-engines + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Mount MySQL Secrets using CSI Driver + +## Kubernetes Secrets Store CSI Driver + +Secrets Store CSI driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a [Container Storage Interface (CSI)](https://kubernetes-csi.github.io/docs/) volume. + +The Secrets Store CSI driver `secrets-store.csi.k8s.io` allows Kubernetes to mount multiple secrets, keys, and certs stored in enterprise-grade external secrets stores into their pods as a volume. Once the Volume is attached, the data in it is mounted into the container’s file system. + +![Secrets-store CSI architecture](/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg) + +When the `Pod` is created through the K8s API, it’s scheduled on to a node. The `kubelet` process on the node looks at the pod spec & see if there's any `volumeMount` request. The `kubelet` issues an `RPC` to the `CSI driver` to mount the volume. The `CSI driver` creates & mounts `tmpfs` into the pod. Then the `CSI driver` issues a request to the `Provider`. The provider talks to the external secrets store to fetch the secrets & write them to the pod volume as files. At this point, volume is successfully mounted & the pod starts running. + +You can read more about the Kubernetes Secrets Store CSI Driver [here](https://secrets-store-csi-driver.sigs.k8s.io/). + +## Consuming Secrets + +At first, you need to have a Kubernetes 1.16 or later cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). To check the version of your cluster, run: + +```bash +$ kubectl version --short +Client Version: v1.21.2 +Server Version: v1.21.1 +``` + +Before you begin: + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). +- Install Secrets Store CSI driver for Kubernetes secrets in your cluster from [here](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html). +- Install Vault Specific CSI provider from [here](https://github.com/hashicorp/vault-csi-provider) + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial stored in [examples](/docs/v2025.11.21/examples/guides/secret-engines/mysql) folder in GitHub repository [KubeVault/docs](https://github.com/kubevault/kubevault) + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. And we also have the service account that the Vault server can authenticate. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable & Configure MySQL SecretEngine + +### Enable MySQL SecretEngine + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mysql/secretengine.yaml +secretengine.engine.kubevault.com/mysql-engine created +``` + +### Create MySQLRole + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mysql/secretenginerole.yaml +mysqlrole/mysql-superuser-role created +``` + +Let's say pod's service account name is `test-user-account` located in `demo` namespace. We need to create a [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) and a [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) so that the pod has access to read secrets from the Vault server. + +### Create Service Account for Pod + +Let's create the service account `test-user-account` which will be used in VaultPolicyBinding. +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mysql/serviceaccount.yaml +serviceaccount/test-user-account created + +$ kubectl get serviceaccount -n demo +NAME SECRETS AGE +test-user-account 1 4h10m +``` + +### Create SecretRoleBinding for Pod's Service Account + +SecretRoleBinding will create VaultPolicy and VaultPolicyBinding inside vault. +When a VaultPolicyBinding object is created, the KubeVault operator create an auth role in the Vault server. The role name is generated by the following naming format: `k8s.(clusterName or -).namespace.name`. Here, it is `k8s.kubevault.com.demo.postgres-superuser-role`. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: MySQLRole + name: mysql-superuser-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo +``` + +Let's create SecretRoleBinding: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mysql/secret-role-binding.yaml +secretrolebinding.engine.kubevault.com/secret-role-binding created +``` +Check if the VaultPolicy and the VaultPolicyBinding are successfully registered to the Vault server: + +```bash +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 8s + +$ kubectl get vaultpolicybinding -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 10s +``` + +## Mount secrets into a Kubernetes pod + +So, we can create `SecretProviderClass` now. You can read more about `SecretProviderClass` [here](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#secretproviderclass). + +### Create SecretProviderClass + +Create `SecretProviderClass` object with the following content: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.mysql-reader-role" + objects: | + - objectName: "mysql-creds-username" + secretPath: "your-database-path/creds/k8s.-.demo.mysql-superuser-role" + secretKey: "username" + - objectName: "mysql-creds-password" + secretPath: "your-database-path/creds/k8s.-.demo.mysql-superuser-role" + secretKey: "password" + +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mysql/secretproviderclass.yaml +secretproviderclass.secrets-store.csi.x-k8s.io/vault-db-provider created +``` + +NOTE: The `SecretProviderClass` needs to be created in the same namespace as the pod. + +### Create Pod + +Now we can create a `Pod` to consume the `MySQL` secrets. When the `Pod` is created, the `Provider` fetches the secret and writes them to Pod's volume as files. At this point, the volume is successfully mounted and the `Pod` starts running. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/mysql-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mysql/pod.yaml +pod/demo-app created +``` +## Test & Verify + +Check if the Pod is running successfully, by running: + +```bash +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +demo-app 1/1 Running 0 11s +``` + +### Verify Secret + +If the Pod is running successfully, then check inside the app container by running + +```bash +$ kubectl exec -it -n demo pod/demo-app -- /bin/sh +/ # ls /secrets-store/mysql-creds +mysql-creds-password mysql-creds-username + +/ # cat /secrets-store/mysql-creds/mysql-creds-password +TAu2Zvg1WYE07W8Uf-nW + +/ # cat /secrets-store/mysql-creds/mysql-creds-username +v-kubernetes-test-k8s.-.demo.mysql-s-iPkxiH80Ollq2QgF82Ab-1629178048 + +/ # exit +``` + +So, we can see that the secret `db-username` and `db-password` is mounted into the pod, where the secret key is mounted as file and value is the content of that file. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted + +``` diff --git a/content/docs/v2025.11.21/guides/secret-engines/mysql/overview.md b/content/docs/v2025.11.21/guides/secret-engines/mysql/overview.md new file mode 100644 index 000000000..4f6f3a1bd --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/mysql/overview.md @@ -0,0 +1,337 @@ +--- +title: Manage MySQL credentials using the KubeVault operator +menu: + docs_v2025.11.21: + identifier: overview-mysql + name: Overview + parent: mysql-secret-engines + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Manage MySQL credentials using the KubeVault operator + +MySQL is one of the supported plugins for the database secrets engine. This plugin generates database credentials dynamically based on configured roles for the MySQL database. You can easily manage [MySQL secret engine](https://www.vaultproject.io/docs/secrets/databases/mysql-maria.html) using the KubeVault operator. + +![MySQL secret engine](/docs/v2025.11.21/images/guides/secret-engines/mysql/mysql_secret_engine_guide.svg) + +You need to be familiar with the following CRDs: + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) +- [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) +- [MySQLRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mysql) + +## Before you begin + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +In this tutorial, we are going to create a [role](https://www.vaultproject.io/docs/secrets/databases/mysql-maria#setup) using MySQL and issue credential using SecretAccessRequest. + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable and Configure MySQL Secret Engine + +When a [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) crd object is created, the KubeVault operator will enable a secret engine on specified path and configure the secret engine with given configurations. + +A sample SecretEngine object for the MySQL secret engine: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: mysql-engine + namespace: demo +spec: + vaultRef: + name: vault + mysql: + databaseRef: + name: mysql + namespace: demo + pluginName: "mysql-database-plugin" +``` + +Let's deploy SecretEngine: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mysql/secretengine.yaml +secretengine.engine.kubevault.com/mysql-engine created +``` + +Wait till the status become `Success`: + +```bash +$ kubectl get secretengines -n demo +NAME STATUS AGE +mysql-engine Success 10s +``` + +Since the status is `Success`, the MySQL secret engine is enabled and successfully configured. You can use `kubectl describe secretengine -n ` to check for error events, if any. + +## Create MySQL Role + +By using [MySQLRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/mysql), you can create a [role](https://www.vaultproject.io/docs/secrets/databases/mysql-maria#setup) on the Vault server in Kubernetes native way. + +A sample MySQLRole object is given below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: MySQLRole +metadata: + name: mysql-superuser-role + namespace: demo +spec: + secretEngineRef: + name: sql-secrt-engine + creationStatements: + - "CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';" + - "GRANT SELECT ON *.* TO '{{name}}'@'%';" + defaultTTL: 1h + maxTTL: 24h +``` + +Let's deploy MySQLRole: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mysql/secretenginerole.yaml +mongodbrole.engine.kubevault.com/mysql-superuser-role created + +$ kubectl get mysqlrole -n demo +NAME STATUS AGE +mysql-superuser-role Success 34m +``` + +You can also check from Vault that the role is created. +To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +```bash +$ vault list your-database-path/roles +Keys +---- +k8s.-.demo.mysql-superuser-role + +$ vault read your-database-path/roles/k8s.-.demo.mysql-superuser-role +Key Value +--- ----- +creation_statements [CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; GRANT SELECT ON *.* TO '{{name}}'@'%';] +db_name k8s.-.demo.mysql +default_ttl 1h +max_ttl 24h +renew_statements [] +revocation_statements [] +rollback_statements [] +``` + +If we delete the MySQL, then the respective role will be deleted from the Vault. + +```bash +$ kubectl delete mysqlrole -n demo mysql-superuser-role +mysqlrole.engine.kubevault.com "mysql-superuser-role" deleted +``` + +Check from Vault whether the role exists: + +```bash +$ vault read your-database-path/roles/k8s.-.demo.mysql-superuser-role +No value found at your-database-path/roles/k8s.-.demo.mysql-superuser-role + +$ vault list your-database-path/roles +No value found at your-database-path/roles/ +``` + +## Generate MySQL credentials + +Here, we are going to make a request to Vault for MySQL credentials by creating `mysql-cred-rqst` SecretAccessRequest in `demo` namespace. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: mysql-cred-rqst + namespace: demo +spec: + roleRef: + kind: MySQLRole + name: mysql-superuser-role + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +``` + +Here, `spec.roleRef` is the reference of MySQL against which credentials will be issued. `spec.subjects` is the reference to the object or user identities a role binding applies to it will have read access of the credential secret. + +Now, we are going to create SecretAccessRequest. + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/mysql/mysqlaccessrequest.yaml +secretaccessrequest.engine.kubevault.com/mysql-cred-rqst created + +$ kubectl get secretaccessrequest -n demo +NAME AGE +mysql-cred-rqst 72m +``` + +Database credentials will not be issued until it is approved. The KubeVault operator will watch for the approval in the `status.conditions[].type` field of the request object. You can use [KubeVault CLI](https://github.com/kubevault/cli), a [kubectl plugin](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/), to approve or deny SecretAccessRequest. + +```bash +# using KubeVault CLI as kubectl plugin to approve request +$ kubectl vault approve secretaccessrequest mysql-cred-rqst -n demo +approved + +$ kubectl get secretaccessrequest -n demo mysql-cred-rqst -o yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: mysql-cred-rqst + namespace: demo +spec: + roleRef: + kind: MySQLRole + name: mysql-superuser-role + namespace: demo + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +status: + conditions: + - lastUpdateTime: "2020-11-18T06:41:57Z" + message: This was approved by kubectl vault approve secretaccessrequest + reason: KubectlApprove + type: Approved + lease: + duration: 1h0m0s + id: your-database-path/creds/k8s.-.demo.mysql-superuser-role/ni3TCo2HkSwCUb8kmQuvIDdx + renewable: true + secret: + name: mysql-cred-rqst-gy66wq +``` + +Once SecretAccessRequest is approved, the KubeVault operator will issue credentials from Vault and create a secret containing the credential. It will also create a role and rolebinding so that `spec.subjects` can access secret. You can view the information in the `status` field. + +```bash +$ kubectl get secretaccessrequest mysql-cred-rqst -n demo -o json | jq '.status' +{ + "conditions": [ + { + "lastUpdateTime": "2019-11-18T06:41:57Z", + "message": "This was approved by kubectl vault approve secretaccessrequest", + "reason": "KubectlApprove", + "type": "Approved" + } + ], + "lease": { + "duration": "1h0m0s", + "id": "your-database-path/creds/k8s.-.demo.mysql-superuser-role/ni3TCo2HkSwCUb8kmQuvIDdx", + "renewable": true + }, + "secret": { + "name": "mysql-cred-rqst-gy66wq" + } +} + +$ kubectl get secret -n demo mysql-cred-rqst-gy66wq -o yaml +apiVersion: v1 +data: + password: QTFhLVBkZGlsZFFxa0o1cnlvR20= + username: di1rdWJlcm5ldGVzLWRlbW8TE1NzQwNTkzMTc= +kind: Secret +metadata: + name: mysql-cred-rqst-gy66wq + namespace: demo + ownerReferences: + - apiVersion: engine.kubevault.com/v1alpha1 + controller: true + kind: SecretAccessRequest + name: mysql-cred-rqst + uid: 54ce63ca-d0e7-4b97-9085-b52eb3cb334f +type: Opaque +``` + +If SecretAccessRequest is deleted, then credential lease (if any) will be revoked. + +```bash +$ kubectl delete secretaccessrequest -n demo mysql-cred-rqst +secretaccessrequest.engine.kubevault.com "mysql-cred-rqst" deleted +``` + +If SecretAccessRequest is `Denied`, then the KubeVault operator will not issue any credential. + +```bash +$ kubectl vault deny secretaccessrequest mysql-cred-rqst -n demo + Denied +``` + +> Note: Once SecretAccessRequest is `Approved`, you cannot change `spec.roleRef` and `spec.subjects` field. diff --git a/content/docs/v2025.11.21/guides/secret-engines/pki/_index.md b/content/docs/v2025.11.21/guides/secret-engines/pki/_index.md new file mode 100755 index 000000000..f372266c9 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/pki/_index.md @@ -0,0 +1,17 @@ +--- +title: PKI | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: pki-secret-engines + name: PKI + parent: secret-engines-guides + weight: 50 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/secret-engines/pki/csi-driver.md b/content/docs/v2025.11.21/guides/secret-engines/pki/csi-driver.md new file mode 100644 index 000000000..8d30e2bc2 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/pki/csi-driver.md @@ -0,0 +1,406 @@ +--- +title: Mount PKI(certificates) Secrets into Kubernetes pod using CSI Driver +menu: + docs_v2025.11.21: + identifier: csi-driver-pki + name: CSI Driver + parent: pki-secret-engines + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Mount PKI(certificates) Secrets using CSI Driver + +## Kubernetes Secrets Store CSI Driver + +Secrets Store CSI driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a [Container Storage Interface (CSI)](https://kubernetes-csi.github.io/docs/) volume. + +The Secrets Store CSI driver `secrets-store.csi.k8s.io` allows Kubernetes to mount multiple secrets, keys, and certs stored in enterprise-grade external secrets stores into their pods as a volume. Once the Volume is attached, the data in it is mounted into the container’s file system. + +![Secrets-store CSI architecture](/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg) + +When the `Pod` is created through the K8s API, it’s scheduled on to a node. The `kubelet` process on the node looks at the pod spec & see if there's any `volumeMount` request. The `kubelet` issues an `RPC` to the `CSI driver` to mount the volume. The `CSI driver` creates & mounts `tmpfs` into the pod. Then the `CSI driver` issues a request to the `Provider`. The provider talks to the external secrets store to fetch the secrets & write them to the pod volume as files. At this point, volume is successfully mounted & the pod starts running. + +You can read more about the Kubernetes Secrets Store CSI Driver [here](https://secrets-store-csi-driver.sigs.k8s.io/). + +## Consuming Secrets + +At first, you need to have a Kubernetes 1.16 or later cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). To check the version of your cluster, run: + +```bash +$ kubectl version --short +Client Version: v1.21.2 +Server Version: v1.21.1 +``` + +Before you begin: + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). +- Install Secrets Store CSI driver for Kubernetes secrets in your cluster from [here](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial stored in [examples](/docs/v2025.11.21/examples/guides/secret-engines/pki) folder in GitHub repository [KubeVault/docs](https://github.com/kubevault/kubevault) + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. And we also have the service account that the Vault server can authenticate. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable and Configure PKI Secret Engine + +We will use the [Vault CLI](https://www.vaultproject.io/docs/commands/#vault-commands-cli-) throughout the tutorial to [enable and configure](https://www.vaultproject.io/docs/secrets/pki/index.html#setup) the PKI secret engine. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +To use secret from `PKI` secret engine, you have to perform the following steps. + +### Enable PKI Secret Engine + +To enable `PKI` secret engine run the following command. + +```bash +$ vault secrets enable pki +Success! Enabled the pki secrets engine at: pki/ +``` + +Increase the TTL by tuning the secrets engine. The default value of 30 days may be too short, so increase it to 1 year: + +```bash +$ vault secrets tune -max-lease-ttl=8760h pki +Success! Tuned the secrets engine at: pki/ +``` + +### Configure CA Certificate and Private Key + +Configure a CA certificate and private key. Vault can accept an existing key pair, or it can generate its own self-signed root. + +```bash +$ vault write pki/root/generate/internal \ + common_name=my-website.com \ + ttl=8760h +Key Value +--- ----- +certificate -----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIUEDmnAmC0siISlrezD3/CeUXTSfswDQYJKoZIhvcNAQEL +... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... +CsFVu+vfMM9XEMYeKHRWAq9onJFyGuwKGhF0/7RbZ3EunTj6Zph+UMucGoL4xfXj +ITltdU1N4JPvihQq+8Omryay +-----END CERTIFICATE----- +expiration 1606200496 +issuing_ca -----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIUEDmnAmC0siISlrezD3/CeUXTSfswDQYJKoZIhvcNAQEL +... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... +CsFVu+vfMM9XEMYeKHRWAq9onJFyGuwKGhF0/7RbZ3EunTj6Zph+UMucGoL4xfXj +ITltdU1N4JPvihQq+8Omryay +-----END CERTIFICATE----- +serial_number 10:39:a7:02:60:b4:b2:22:12:96:b7:b3:0f:7f:c2:79:45:d3:49:fb +``` + +### Configure a PKI Role + +We need to configure a role that maps a name in vault to a procedure for generating certificate. When users of machines generate credentials, they are generated agains this role: + +```bash +$ vault write pki/roles/example-dot-com \ + allowed_domains=my-website.com \ + allow_subdomains=true \ + max_ttl=72h +Success! Data written to: pki/roles/example-dot-com +``` + +### Create Service Account for Pod + +Let's create the service account `test-user-account` which will be used in VaultPolicyBinding. +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/pki/serviceaccount.yaml +serviceaccount/test-user-account created + +$ kubectl get serviceaccount -n demo +NAME SECRETS AGE +test-user-account 1 4h10m +``` + +### Create VaultPolicy and VaultPolicyBinding for Pod's Service Account + +When a VaultPolicyBinding object is created, the KubeVault operator create an auth role in the Vault server. The role name is generated by the following naming format: `k8s.(clusterName or -).namespace.name`. Here, it is `k8s.-.demo.pki-se-role`. + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: pki-se-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "pki/issue/*" { + capabilities = ["update"] + } +--- +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: pki-se-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: pki-se-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "test-user-account" + serviceAccountNamespaces: + - "demo" +``` + +Let's create VaultPolicy and VaultPolicyBinding: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/pki/policy.yaml +vaultpolicy.policy.kubevault.com/pki-se-policy created + +$ kubectl apply -f docs/examples/guides/secret-engines/pki/policybinding.yaml +vaultpolicybinding.policy.kubevault.com/pki-se-role created +``` + +Check if the VaultPolicy and the VaultPolicyBinding are successfully registered to the Vault server: + +```bash +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +pki-se-policy Success 8s + +$ kubectl get vaultpolicybinding -n demo +NAME STATUS AGE +pki-se-role Success 10s +``` + +## Mount Certificates into a Kubernetes Pod + +So, we can create `SecretProviderClass` now. You can read more about `SecretProviderClass` [here](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#secretproviderclass). + +### Create SecretProviderClass + +Create `SecretProviderClass` object with the following content: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.pki-se-role" + objects: | + - objectName: "certificate" + secretPath: "pki/issue/example-dot-com" + secretKey: "certificate" + secretArgs: + common_name: "www.my-website.com" + ttl: 24h + method: "POST" + + - objectName: "issuing_ca" + secretPath: "pki/issue/example-dot-com" + secretKey: "issuing_ca" + secretArgs: + common_name: "www.my-website.com" + ttl: 24h + method: "POST" + + - objectName: "private_key" + secretPath: "pki/issue/example-dot-com" + secretKey: "private_key" + secretArgs: + common_name: "www.my-website.com" + ttl: 24h + method: "POST" + + - objectName: "private_key_type" + secretPath: "pki/issue/example-dot-com" + secretKey: "private_key_type" + secretArgs: + common_name: "www.my-website.com" + ttl: 24h + method: "POST" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/pki/secretproviderclass.yaml +secretproviderclass.secrets-store.csi.x-k8s.io/vault-db-provider created +``` + +Here, you can also pass the following parameters optionally to issue the certificate + +- `common_name` (string: ) – Specifies the requested CN for the certificate. If the CN is allowed by role policy, it will be issued. + +- `alt_names` (string: "") – Specifies requested Subject Alternative Names, in a comma-delimited list. These can be host names or email addresses; they will be parsed into their respective fields. If any requested names do not match role policy, the entire request will be denied. + +- `ip_sans` (string: "") – Specifies requested IP Subject Alternative Names, in a comma-delimited list. Only valid if the role allows IP SANs (which is the default). + +- `uri_sans` (string: "") – Specifies the requested URI Subject Alternative Names, in a comma-delimited list. + +- `other_sans` (string: "") – Specifies custom OID/UTF8-string SANs. These must match values specified on the role in allowed_other_sans (globbing allowed). The format is the same as OpenSSL: ;: where the only current valid type is UTF8. This can be a comma-delimited list or a JSON string slice. + +- `ttl` (string: "") – Specifies requested Time To Live. Cannot be greater than the role's max_ttl value. If not provided, the role's ttl value will be used. Note that the role values default to system values if not explicitly set. + +- `format` (string: "") – Specifies the format for returned data. Can be pem, der, or pem_bundle; defaults to pem. If der, the output is base64 encoded. If pem_bundle, the certificate field will contain the private key and certificate, concatenated; if the issuing CA is not a Vault-derived self-signed root, this will be included as well. + +- `private_key_format` (string: "") – Specifies the format for marshaling the private key. Defaults to der which will return either base64-encoded DER or PEM-encoded DER, depending on the value of format. The other option is pkcs8 which will return the key marshalled as PEM-encoded PKCS8. + +- `exclude_cn_from_sans` (bool: false) – If true, the given common_name will not be included in DNS or Email Subject Alternate Names (as appropriate). Useful if the CN is not a hostname or email address, but is instead some human-readable identifier. + +NOTE: The `SecretProviderClass` needs to be created in the same namespace as the pod. + +### Create Pod + +Now we can create a `Pod` to consume the `PKI` secrets. When the `Pod` is created, the `Provider` fetches the secret and writes them to Pod's volume as files. At this point, the volume is successfully mounted and the `Pod` starts running. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/pki-assets" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/pki/pod.yaml +pod/demo-app created +``` + +## Test & Verify + +Check if the Pod is running successfully, by running: + +```bash +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +demo-app 1/1 Running 0 11s +``` + +### Verify Secret + +If the Pod is running successfully, then check inside the app container by running + +```bash +$ kubectl exec -it -n test pod/demo-app -- /bin/sh + +/ # ls /secrets-store/pki-assets +certificate issuing_ca private_key private_key_type + +/ # cat /secrets-store/pki-assets/certificate +-----BEGIN CERTIFICATE----- +MIIDVjCCAj6gAwIBAgIUNjTBC3qR7Zaj0XrzUc3QEbE+EhgwDQYJKoZIhvcNAQEL +BQAwGTEXMBUGA1UEAxMObXktd2Vic2l0ZS5jb20wHhcNMTkxMjEzMTExNDIwWhcN +..... .... .... .... .... .... .... .... .... .... .... .... ... +bo901cITjNyCTbAF2401pYFZ4rSlxhcuAvc7c27uqvKEh2/ctMGRkvPVygbPdvB8 +LfCskfX0sk8PQiEznlmYlChK3KNsEp+xSCyjU+pDEw8AcDXwE6vVFft/fRX0oiHH +KIzTZ7R/QKUkLisloMUHStINISAehglLZTJjo79jB7GN66wyqP+E8iRLEYFAAsb0 +aZ5wuSTYEpqOuP6G1tOdhiE7iptFu9Wg9dKtmXkZnc0iTBL60xMUUapH +-----END CERTIFICATE----- +``` + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted + +``` diff --git a/content/docs/v2025.11.21/guides/secret-engines/pki/overview.md b/content/docs/v2025.11.21/guides/secret-engines/pki/overview.md new file mode 100644 index 000000000..d5c6f1da8 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/pki/overview.md @@ -0,0 +1,458 @@ +--- +title: Manage PKI(certificates) secrets using the KubeVault operator +menu: + docs_v2025.11.21: + identifier: overview-pki + name: Overview + parent: pki-secret-engines + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Manage PKI(certificates) secrets using the KubeVault operator + +The [PKI secrets engine](https://www.vaultproject.io/docs/secrets/pki/index.html) generates dynamic X.509 certificates. With this secrets engine, services can get certificates without going through the usual manual process of generating a private key and CSR, submitting to a CA, and waiting for a verification and signing process to complete. Vault's built-in authentication and authorization mechanisms provide the verification functionality. + +You can easily manage [PKI secret engine](https://www.vaultproject.io/docs/secrets/pki/index.html) using the KubeVault operator. + +You should be familiar with the following CRD: + +- [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) +- [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) + +## Before you begin + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +In this tutorial, we are going to demonstrate the use of the PKI secret engine. + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Use PKI Secret Engine as Root User + +Here, we are going to use the Vault root token to perform authentication to the Vault server. We will use the [Vault CLI](https://www.vaultproject.io/docs/commands/#vault-commands-cli-) throughout the tutorial. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +Export the root token as environment variable: + +```bash +$ export VAULT_TOKEN=s.diWLjSzmfSmF0qUNYV3qOIeX +``` + +Enable the PKI secrets engine: + +```bash +$ vault secrets enable pki +Success! Enabled the pki secrets engine at: pki/ +``` + +Increase the TTL by tuning the secrets engine. The default value of 30 days may be too short, so increase it to 1 year: + +```bash +$ vault secrets tune -max-lease-ttl=8760h pki +Success! Tuned the secrets engine at: pki/ +``` + +Configure a CA certificate and private key: + +```bash +$ vault write pki/root/generate/internal \ + common_name=my-website.com \ + ttl=8760h +Key Value +--- ----- +certificate -----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIUEDmnAmC0siISlrezD3/CeUXTSfswDQYJKoZIhvcNAQEL +... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... +CsFVu+vfMM9XEMYeKHRWAq9onJFyGuwKGhF0/7RbZ3EunTj6Zph+UMucGoL4xfXj +ITltdU1N4JPvihQq+8Omryay +-----END CERTIFICATE----- +expiration 1606200496 +issuing_ca -----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIUEDmnAmC0siISlrezD3/CeUXTSfswDQYJKoZIhvcNAQEL +... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... +CsFVu+vfMM9XEMYeKHRWAq9onJFyGuwKGhF0/7RbZ3EunTj6Zph+UMucGoL4xfXj +ITltdU1N4JPvihQq+8Omryay +-----END CERTIFICATE----- +serial_number 10:39:a7:02:60:b4:b2:22:12:96:b7:b3:0f:7f:c2:79:45:d3:49:fb +``` + +Configure a role that maps a name in Vault to a procedure for generating a certificate. When users or machines generate credentials, they are generated against this role: + +```bash +$ vault write pki/roles/example-dot-com \ + allowed_domains=my-website.com \ + allow_subdomains=true \ + max_ttl=72h +Success! Data written to: pki/roles/example-dot-com +``` + +Generate a new credential by writing to the /issue endpoint with the name of the role: + +```bash +$ vault write pki/issue/example-dot-com \ + common_name=www.my-website.com +Key Value +--- ----- +certificate -----BEGIN CERTIFICATE----- +MIIDVjCCAj6gAwIBAgIUWQhPLW6R/nk/3x3XReHC1Ze4BWUwDQYJKoZIhvcNAQEL +... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... +TSuguIiSBt5NN0ou4aY01FbeJJOHZhtpj31XdXOCAKR40lPCmWtEUAbcuEhLlkm+ +vmhNYxBqkx33jEIMxk95P4eKIYPyr45/8o7bV1jq7G26aBzj1Mjd0JmU +-----END CERTIFICATE----- +expiration 1574924103 +issuing_ca -----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIUEDmnAmC0siISlrezD3/CeUXTSfswDQYJKoZIhvcNAQEL +... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... +CsFVu+vfMM9XEMYeKHRWAq9onJFyGuwKGhF0/7RbZ3EunTj6Zph+UMucGoL4xfXj +ITltdU1N4JPvihQq+8Omryay +-----END CERTIFICATE----- +private_key -----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAuK7V4GuoHSF8pnlr4hApeU7V3zpuQ2rWt3pXgi9TPBCmIuye +... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ++o8HetGW5xWvuQ/ObkiSzdQ8nxMyiQj/whe4riYriOw1fYwPrjZfxTm1jsyEmbbm +gYewhfHP3hOgTCVu3SjhvOXS3pnW7hUP4wtvpLLdRumEUM/fK7pwNg== +-----END RSA PRIVATE KEY----- +private_key_type rsa +serial_number 59:008:4f:2d:6e:91:fe:79:3f:df:1d:d7:45:e1:c2:d5:97:b8:05:65 +``` + +For more details visit the [official Vault documentation](https://www.vaultproject.io/docs/secrets/pki/index.html#setup). + +## Use PKI Secret Engine as Non-root User + +Here, we are going to create a Kubernetes service account and give it limited access (i.e only PKI secret engine) from the Vault using the VaultPolicy and the VaultPolicyBinding. + +### Create Kubernetes Service Account + +Create a service account `pki-admin` to the `demo` namespace: + +```bash +$ kubectl create serviceaccount -n demo pki-admin +serviceaccount/pki-admin created + +# get service account JWT token which will be required while performing +# login operation to the Vault +$ kubectl get secrets -n demo pki-admin-token-26kwb -o jsonpath="{.data.token}" | base64 --decode; +eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZW1vIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InBraS1hZG1pbi10b2tlbi0yNmt3YiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJwa2ktYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJkYmVkZDQ2Ni0yYzc0LTQ0OGItOTBlZS01MDlkNGI4MTJjOTEiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVtbzpwa2ktYWRtaW4ifQ.ce7OqA05nsfBMRsEOiG1Lje_mOBdUZRKALB9Sc9LVqjKIJZHdxvZ7NT4ZKrIyPEe02aItzxlXLAP4Fa8dUMshZuNyuxBYN7p2qHRCwVKHqOuz8LdRQWypKiLozL9v0DHk-vbFWFcm0eye57vJBFtriYyYRUA84WZhxRb9wz-f8z7PSmO2mpjkrICt7wi48j-4FObdhFWk6HAKXFD7bCzL4j3CWUcx2wTIsnOEz9SifjYZuGaog6tpWhnj-guEKpXJzBLAoMBU0Vr3U7Zv_z1qvKFF4ZherUBxSOMo27lL2xbhkpbW2wf_DCAjLx8pScoh9mxv7AK2WJCHeA0JRzrug +``` + +### Create VaultPolicy and VaultPolicyBinding + +A sample VaultPolicy object with necessary path permission for the PKI secret engine: + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: pki-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "sys/mounts" { + capabilities = ["read", "list"] + } + + path "sys/mounts/*" { + capabilities = ["create", "read", "update", "delete"] + } + + path "pki/*" { + capabilities = ["read","create", "list", "update", "delete"] + } + + path "sys/leases/revoke/*" { + capabilities = ["update"] + } +``` + +Create VaultPolicy and check status: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/pki/policy.yaml +vaultpolicy.policy.kubevault.com/pki-policy created + +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +pki-policy Success 3m15s +``` + +A sample VaultPolicyBinding object that binds the `pki-policy` to the `pki-admin` service account: + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: pki-admin-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: pki-policy + subjectRef: + kubernetes: + serviceAccountNames: + - "pki-admin" + serviceAccountNamespaces: + - "demo" + ttl: "1000" + maxTTL: "2000" + period: "1000" +``` + +Create VaultPolicyBinding and check status: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/pki/policyBinding.yaml +vaultpolicybinding.policy.kubevault.com/pki-admin-role created + +$ kubectl get vaultpolicybindings -n demo +NAME STATUS AGE +pki-admin-role Success 43m +``` + +### Login Vault and Use PKI Secret Engine + +To resolve the naming conflict, name of the policy and role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +List Vault policies and Kubernetes auth roles: + +```bash +$ vault list sys/policy +Keys +---- +k8s.-.demo.pki-policy + +$ vault read sys/policy/k8s.-.demo.pki-policy +Key Value +--- ----- +name k8s.-.demo.pki-policy +rules path "sys/mounts" { + capabilities = ["read", "list"] +} + +path "sys/mounts/*" { + capabilities = ["create", "read", "update", "delete"] +} + +path "pki/*" { + capabilities = ["read","create", "list", "update", "delete"] +} + +path "sys/leases/revoke/*" { + capabilities = ["update"] +} + +$ vault list auth/kubernetes/role +Keys +---- +k8s.-.demo.pki-admin-role + +$ vault read auth/kubernetes/role/k8s.-.demo.pki-admin-role +Key Value +--- ----- +bound_service_account_names [pki-admin] +bound_service_account_namespaces [demo] +max_ttl 33m20s +period 16m40s +policies [k8s.-.demo.pki-policy] +token_bound_cidrs [] +token_explicit_max_ttl 0s +token_max_ttl 33m20s +token_no_default_policy false +token_num_uses 0 +token_period 16m40s +token_policies [k8s.-.demo.pki-policy] +token_ttl 16m40s +token_type default +ttl 16m40s +``` + +So, we can see that the `pki-policy` is added to the `pki-admin-role`. + +Now, login to the Vault using `pki-admin`'s JWT token under `pki-admin-role` role. + +```bash +$ vault write auth/kubernetes/login \ + role=k8s.-.demo.pki-admin-role \ + jwt=eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZW1vIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InBraS1hZG1pbi10b2tlbi0yNmt3YiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJwa2ktYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJkYmVkZDQ2Ni0yYzc0LTQ0OGItOTBlZS01MDlkNGI4MTJjOTEiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVtbzpwa2ktYWRtaW4ifQ.ce7OqA05nsfBMRsEOiG1Lje_mOBdUZRKALB9Sc9LVqjKIJZHdxvZ7NT4ZKrIyPEe02aItzxlXLAP4Fa8dUMshZuNyuxBYN7p2qHRCwVKHqOuz8LdRQWypKiLozL9v0DHk-vbFWFcm0eye57vJBFtriYyYRUA84WZhxRb9wz-f8z7PSmO2mpjkrICt7wi48j-4FObdhFWk6HAKXFD7bCzL4j3CWUcx2wTIsnOEz9SifjYZuGaog6tpWhnj-guEKpXJzBLAoMBU0Vr3U7Zv_z1qvKFF4ZherUBxSOMo27lL2xbhkpbW2wf_DCAjLx8pScoh9mxv7AK2WJCHeA0JRzrug + +Key Value +--- ----- +token s.ZPu4zcyaajjpxtS1t8fnh2LV +token_accessor 5OknOf72h8WnP1v0I1C01626 +token_duration 16m40s +token_renewable true +token_policies ["default" "k8s.-.demo.pki-policy"] +identity_policies [] +policies ["default" "k8s.-.demo.pki-policy"] +token_meta_role k8s.-.demo.pki-admin-role +token_meta_service_account_name pki-admin +token_meta_service_account_namespace demo +token_meta_service_account_secret_name pki-admin-token-26kwb +token_meta_service_account_uid dbedd466-2c74-448b-90ee-509d4b812c91 +``` + +Export the new Vault token as an environment variable: + +```bash +export VAULT_TOKEN=(kubectl vault root-token get vaultserver vault -n demo --value-only) +``` + +Now generate a new certificate using the PKI secret engine. + +Enable the PKI secrets engine: + +```bash +$ vault secrets enable pki +Success! Enabled the pki secrets engine at: pki/ +``` + +Increase the TTL by tuning the secrets engine. The default value of 30 days may be too short, so increase it to 1 year: + +```bash +$ vault secrets tune -max-lease-ttl=8760h pki +Success! Tuned the secrets engine at: pki/ +``` + +Configure a CA certificate and private key: + +```bash +$ vault write pki/root/generate/internal \ + common_name=my-website.com \ + ttl=8760h +Key Value +--- ----- +certificate -----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIUEDmnAmC0siISlrezD3/CeUXTSfswDQYJKoZIhvcNAQEL +... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... +CsFVu+vfMM9XEMYeKHRWAq9onJFyGuwKGhF0/7RbZ3EunTj6Zph+UMucGoL4xfXj +ITltdU1N4JPvihQq+8Omryay +-----END CERTIFICATE----- +expiration 1606200496 +issuing_ca -----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIUEDmnAmC0siISlrezD3/CeUXTSfswDQYJKoZIhvcNAQEL +... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... +CsFVu+vfMM9XEMYeKHRWAq9onJFyGuwKGhF0/7RbZ3EunTj6Zph+UMucGoL4xfXj +ITltdU1N4JPvihQq+8Omryay +-----END CERTIFICATE----- +serial_number 10:39:a7:02:60:b4:b2:22:12:96:b7:b3:0f:7f:c2:79:45:d3:49:fb +``` + +Configure a role that maps a name in Vault to a procedure for generating a certificate. When users or machines generate credentials, they are generated against this role: + +```bash +$ vault write pki/roles/example-dot-com \ + allowed_domains=my-website.com \ + allow_subdomains=true \ + max_ttl=72h +Success! Data written to: pki/roles/example-dot-com +``` + +Generate a new credential by writing to the /issue endpoint with the name of the role: + +```bash +$ vault write pki/issue/example-dot-com \ + common_name=www.my-website.com +Key Value +--- ----- +certificate -----BEGIN CERTIFICATE----- +MIIDVjCCAj6gAwIBAgIUWQhPLW6R/nk/3x3XReHC1Ze4BWUwDQYJKoZIhvcNAQEL +... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... +TSuguIiSBt5NN0ou4aY01FbeJJOHZhtpj31XdXOCAKR40lPCmWtEUAbcuEhLlkm+ +vmhNYxBqkx33jEIMxk95P4eKIYPyr45/8o7bV1jq7G26aBzj1Mjd0JmU +-----END CERTIFICATE----- +expiration 1574924103 +issuing_ca -----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIUEDmnAmC0siISlrezD3/CeUXTSfswDQYJKoZIhvcNAQEL +... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... +CsFVu+vfMM9XEMYeKHRWAq9onJFyGuwKGhF0/7RbZ3EunTj6Zph+UMucGoL4xfXj +ITltdU1N4JPvihQq+8Omryay +-----END CERTIFICATE----- +private_key -----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAuK7V4GuoHSF8pnlr4hApeU7V3zpuQ2rWt3pXgi9TPBCmIuye +... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ++o8HetGW5xWvuQ/ObkiSzdQ8nxMyiQj/whe4riYriOw1fYwPrjZfxTm1jsyEmbbm +gYewhfHP3hOgTCVu3SjhvOXS3pnW7hUP4wtvpLLdRumEUM/fK7pwNg== +-----END RSA PRIVATE KEY----- +private_key_type rsa +serial_number 59:008:4f:2d:6e:91:fe:79:3f:df:1d:d7:45:e1:c2:d5:97:b8:05:65 +``` + +For more details visit the [official Vault documentation](https://www.vaultproject.io/docs/secrets/pki/index.html#setup). diff --git a/content/docs/v2025.11.21/guides/secret-engines/postgres/_index.md b/content/docs/v2025.11.21/guides/secret-engines/postgres/_index.md new file mode 100755 index 000000000..55db79922 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/postgres/_index.md @@ -0,0 +1,17 @@ +--- +title: PostgreSQL | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: postgres-secret-engines + name: PostgreSQL + parent: secret-engines-guides + weight: 60 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/secret-engines/postgres/csi-driver.md b/content/docs/v2025.11.21/guides/secret-engines/postgres/csi-driver.md new file mode 100644 index 000000000..3019a73fd --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/postgres/csi-driver.md @@ -0,0 +1,297 @@ +--- +title: Mount PostgreSQL Secrets using CSI Driver +menu: + docs_v2025.11.21: + identifier: csi-driver-postgresql + name: CSI Driver + parent: postgres-secret-engines + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Mount PostgreSQL Secrets using CSI Driver + +## Kubernetes Secrets Store CSI Driver + +Secrets Store CSI driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a [Container Storage Interface (CSI)](https://kubernetes-csi.github.io/docs/) volume. + +The Secrets Store CSI driver `secrets-store.csi.k8s.io` allows Kubernetes to mount multiple secrets, keys, and certs stored in enterprise-grade external secrets stores into their pods as a volume. Once the Volume is attached, the data in it is mounted into the container’s file system. + +![Secrets-store CSI architecture](/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg) + +When the `Pod` is created through the K8s API, it’s scheduled on to a node. The `kubelet` process on the node looks at the pod spec & see if there's any `volumeMount` request. The `kubelet` issues an `RPC` to the `CSI driver` to mount the volume. The `CSI driver` creates & mounts `tmpfs` into the pod. Then the `CSI driver` issues a request to the `Provider`. The provider talks to the external secrets store to fetch the secrets & write them to the pod volume as files. At this point, volume is successfully mounted & the pod starts running. + +You can read more about the Kubernetes Secrets Store CSI Driver [here](https://secrets-store-csi-driver.sigs.k8s.io/). + +## Consuming Secrets + +At first, you need to have a Kubernetes 1.16 or later cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). To check the version of your cluster, run: + +```bash +$ kubectl version --short +Client Version: v1.21.2 +Server Version: v1.21.1 +``` + +Before you begin: + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). +- Install Secrets Store CSI driver for Kubernetes secrets in your cluster from [here](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html). +- Install Vault Specific CSI provider from [here](https://github.com/hashicorp/vault-csi-provider) + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial stored in [examples](/docs/v2025.11.21/examples/guides/secret-engines/postgres) folder in GitHub repository [KubeVault/docs](https://github.com/kubevault/kubevault) + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. And we also have the service account that the Vault server can authenticate. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable & Configure PostgreSQL SecretEngine + +### Enable PostgreSQL SecretEngine + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/postgres/secretengine.yaml +secretengine.engine.kubevault.com/postgres-engine created +``` + +### Create PostgreSQLRole + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/postgres/secretenginerole.yaml +postgresrole.engine.kubevault.com/postgres-superuser-role created +``` + +Let's say pod's service account name is `test-user-account` located in `demo` namespace. We need to create a [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) and a [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) so that the pod has access to read secrets from the Vault server. + +### Create Service Account for Pod + +Let's create the service account `test-user-account` which will be used in VaultPolicyBinding. +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/postgres/serviceaccount.yaml +serviceaccount/test-user-account created + +$ kubectl get serviceaccount -n demo +NAME SECRETS AGE +test-user-account 1 4h10m +``` + +### Create SecretRoleBinding for Pod's Service Account + +SecretRoleBinding will create VaultPolicy and VaultPolicyBinding inside vault. +When a VaultPolicyBinding object is created, the KubeVault operator create an auth role in the Vault server. The role name is generated by the following naming format: `k8s.(clusterName or -).namespace.name`. Here, it is `k8s.kubevault.com.demo.postgres-superuser-role`. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: PostgresRole + name: postgres-superuser-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo +``` + +Let's create SecretRoleBinding: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/postgres/secretrolebinding.yaml +secretrolebinding.engine.kubevault.com/secret-role-binding created +``` +Check if the VaultPolicy and the VaultPolicyBinding are successfully registered to the Vault server: + +```bash +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 8s + +$ kubectl get vaultpolicybinding -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 10s +``` + +## Mount secrets into a Kubernetes pod + +So, we can create `SecretProviderClass` now. You can read more about `SecretProviderClass` [here](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#secretproviderclass). + +### Create SecretProviderClass + +Create `SecretProviderClass` object with the following content: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: "k8s.-.demo.postgres-reader-role" + objects: | + - objectName: "postgres-creds-username" + secretPath: "your-database-path/creds/k8s.-.demo.postgres-superuser-role" + secretKey: "username" + - objectName: "postgres-creds-password" + secretPath: "your-database-path/creds/k8s.-.demo.postgres-superuser-role" + secretKey: "password" + +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/postgres/secretproviderclass.yaml +secretproviderclass.secrets-store.csi.x-k8s.io/vault-db-provider created +``` +NOTE: The `SecretProviderClass` needs to be created in the same namespace as the pod. + +### Create Pod + +Now we can create a `Pod` to consume the `Postgres` secrets. When the `Pod` is created, the `Provider` fetches the secret and writes them to Pod's volume as files. At this point, the volume is successfully mounted and the `Pod` starts running. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/postgres-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" + +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/postgres/pod.yaml +pod/demo-app created +``` +## Test & Verify + +Check if the Pod is running successfully, by running: + +```bash +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +demo-app 1/1 Running 0 11s +``` + +### Verify Secret + +If the Pod is running successfully, then check inside the app container by running + +```bash +$ kubectl exec -it -n demo pod/demo-app -- /bin/sh +/ # ls /secrets-store/postgres-creds +postgres-creds-password postgres-creds-username + +/ # cat /secrets-store/postgres-creds/postgres-creds-password +TAu2Zvg1WYE07W8Uf-nW + +/ # cat /secrets-store/postgres-creds/postgres-creds-username +v-kubernetes-test-k8s.-.demo.postgres-s-iPkxiH80Ollq2QgF82Ab-1629178048 + +/ # exit +``` + +So, we can see that the secret `db-username` and `db-password` is mounted into the pod, where the secret key is mounted as file and value is the content of that file. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted + +``` diff --git a/content/docs/v2025.11.21/guides/secret-engines/postgres/overview.md b/content/docs/v2025.11.21/guides/secret-engines/postgres/overview.md new file mode 100644 index 000000000..bd94c058f --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/postgres/overview.md @@ -0,0 +1,338 @@ +--- +title: Manage PostgreSQL credentials using the KubeVault operator +menu: + docs_v2025.11.21: + identifier: overview-postgresql + name: Overview + parent: postgres-secret-engines + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Manage PostgreSQL credentials using the KubeVault operator + +PostgreSQL is one of the supported plugins for the database secrets engine. This plugin generates database credentials dynamically based on configured roles for the PostgreSQL database. You can easily manage [PostgreSQL secret engine](https://www.vaultproject.io/docs/secrets/databases/postgresql.html) using the KubeVault operator. + +![PostgreSQL secret engine](/docs/v2025.11.21/images/guides/secret-engines/postgresql/postgres_secret_engine_guide.svg) + +You need to be familiar with the following CRDs: + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) +- [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) +- [PostgresRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/postgresrole) + +## Before you begin + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +In this tutorial, we are going to create a [role](https://www.vaultproject.io/docs/secrets/databases/postgresql#setup) using PostgreSQL and issue credential using SecretAccessRequest. + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable and Configure PostgreSQL Secret Engine + +When a [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) crd object is created, the KubeVault operator will enable a secret engine on specified path and configure the secret engine with given configurations. + +A sample SecretEngine object for the PostgreSQL secret engine: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: postgres-engine + namespace: demo +spec: + vaultRef: + name: vault + postgres: + databaseRef: + name: postgres + namespace: demo + pluginName: "postgresql-database-plugin" +``` + +Let's deploy SecretEngine: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/postgres/secretengine.yaml +secretengine.engine.kubevault.com/postgres-engine created +``` + +Wait till the status become `Success`: + +```bash +$ kubectl get secretengines -n demo +NAME STATUS AGE +postgres-engine Success 10s +``` + +Since the status is `Success`, the PostgreSQL secret engine is enabled and successfully configured. You can use `kubectl describe secretengine -n ` to check for error events, if any. + +## Create PostgreSQL Role + +By using [PostgresRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/postgresrole), you can create a [role](https://www.vaultproject.io/docs/secrets/databases/postgresql#setup) on the Vault server in Kubernetes native way. + +A sample PostgresRole object is given below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: PostgresRole +metadata: + name: postgres-superuser-role + namespace: demo +spec: + secretEngineRef: + name: vault + creationStatements: + - "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';" + - "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" + defaultTTL: 1h + maxTTL: 24h + +``` + +Let's deploy PostgresRole: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/postgres/secretenginerole.yaml +postgresrole.engine.kubevault.com/postgres-superuser-role created + +$ kubectl get postgresrole -n demo +NAME STATUS AGE +postgres-superuser-role Success 34m +``` + +You can also check from Vault that the role is created. +To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +```bash +$ vault list your-database-path/roles +Keys +---- +k8s.-.demo.postgres-superuser-role + +$ vault read your-database-path/roles/k8s.-.demo.postgres-superuser-role +Key Value +--- ----- +creation_statements [CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";] +db_name k8s.-.db.postgres +default_ttl 1h +max_ttl 24h +renew_statements [] +revocation_statements [] +rollback_statements [] +``` + +If we delete the PostgreSQL, then the respective role will be deleted from the Vault. + +```bash +$ kubectl delete postgresrole -n demo postgresrole-superuser-role +postgresrolerole.engine.kubevault.com "postgres-superuser-role" deleted +``` + +Check from Vault whether the role exists: + +```bash +$ vault read your-database-path/roles/k8s.-.demo.postgres-superuser-role +No value found at your-database-path/roles/k8s.-.demo.postgres-superuser-role + +$ vault list your-database-path/roles +No value found at your-database-path/roles/ +``` + +## Generate PostgreSQL credentials + +Here, we are going to make a request to Vault for PostgreSQL credentials by creating `postgres-cred-rqst` SecretAccessRequest in `demo` namespace. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: postgres-cred-rqst + namespace: demo +spec: + roleRef: + kind: PostgresRole + name: postgres-superuser-role + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +``` + +Here, `spec.roleRef` is the reference of Postgres against which credentials will be issued. `spec.subjects` is the reference to the object or user identities a role binding applies to it will have read access of the credential secret. + +Now, we are going to create SecretAccessRequest. + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/postgres/mysqlaccessrequest.yaml +secretaccessrequest.engine.kubevault.com/postgres-cred-rqst created + +$ kubectl get secretaccessrequest -n demo +NAME AGE +postgres-cred-rqst 72m +``` + +Database credentials will not be issued until it is approved. The KubeVault operator will watch for the approval in the `status.conditions[].type` field of the request object. You can use [KubeVault CLI](https://github.com/kubevault/cli), a [kubectl plugin](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/), to approve or deny SecretAccessRequest. + +```bash +# using KubeVault CLI as kubectl plugin to approve request +$ kubectl vault approve secretaccessrequest postgres-cred-rqst -n demo +approved + +$ kubectl get secretaccessrequest -n demo postgres-cred-rqst -o yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: postgres-cred-rqst + namespace: demo +spec: + roleRef: + kind: PostgresRole + name: postgres-superuser-role + namespace: demo + subjects: + - kind: ServiceAccount + name: demo-sa + namespace: demo +status: + conditions: + - lastUpdateTime: "2020-11-18T06:41:57Z" + message: This was approved by kubectl vault approve secretaccessrequest + reason: KubectlApprove + type: Approved + lease: + duration: 1h0m0s + id: your-database-path/creds/k8s.-.demo.postgres-superuser-role/ni3TCo2HkSwCUb8kmQuvIDdx + renewable: true + secret: + name: postgres-cred-rqst-gy66wq +``` + +Once SecretAccessRequest is approved, the KubeVault operator will issue credentials from Vault and create a secret containing the credential. It will also create a role and rolebinding so that `spec.subjects` can access secret. You can view the information in the `status` field. + +```bash +$ kubectl get secretaccessrequest postgres-cred-rqst -n demo -o json | jq '.status' +{ + "conditions": [ + { + "lastUpdateTime": "2019-11-18T06:41:57Z", + "message": "This was approved by kubectl vault approve secretaccessrequest", + "reason": "KubectlApprove", + "type": "Approved" + } + ], + "lease": { + "duration": "1h0m0s", + "id": "your-database-path/creds/k8s.-.demo.postgres-superuser-role/ni3TCo2HkSwCUb8kmQuvIDdx", + "renewable": true + }, + "secret": { + "name": "postgres-cred-rqst-gy66wq" + } +} + +$ kubectl get secret -n demo postgres-cred-rqst-gy66wq -o yaml +apiVersion: v1 +data: + password: QTFhLVBkZGlsZFFxa0o1cnlvR20= + username: di1rdWJlcm5ldGVzLWRlbW8TE1NzQwNTkzMTc= +kind: Secret +metadata: + name: postgres-cred-rqst-gy66wq + namespace: demo + ownerReferences: + - apiVersion: engine.kubevault.com/v1alpha1 + controller: true + kind: SecretAccessRequest + name: postgres-cred-rqst + uid: 54ce63ca-d0e7-4b97-9085-b52eb3cb334f +type: Opaque +``` + +If SecretAccessRequest is deleted, then credential lease (if any) will be revoked. + +```bash +$ kubectl delete secretaccessrequest -n demo postgres-cred-rqst +secretaccessrequest.engine.kubevault.com "postgres-cred-rqst" deleted +``` + +If SecretAccessRequest is `Denied`, then the KubeVault operator will not issue any credential. + +```bash +$ kubectl vault deny secretaccessrequest mysql-cred-rqst -n demo + Denied +``` + +> Note: Once SecretAccessRequest is `Approved`, you cannot change `spec.roleRef` and `spec.subjects` field. diff --git a/content/docs/v2025.11.21/guides/secret-engines/redis/_index.md b/content/docs/v2025.11.21/guides/secret-engines/redis/_index.md new file mode 100644 index 000000000..25caa1878 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/redis/_index.md @@ -0,0 +1,17 @@ +--- +title: Redis | Vault Secret Engine +menu: + docs_v2025.11.21: + identifier: redis-secret-engines + name: Redis + parent: secret-engines-guides + weight: 40 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/secret-engines/redis/csi-driver.md b/content/docs/v2025.11.21/guides/secret-engines/redis/csi-driver.md new file mode 100644 index 000000000..0bcf0c723 --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/redis/csi-driver.md @@ -0,0 +1,340 @@ +--- +title: Mount Redis Secrets using CSI Driver +menu: + docs_v2025.11.21: + identifier: csi-driver-redis + name: CSI Driver + parent: redis-secret-engines + weight: 15 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +# Mount Redis Secrets using CSI Driver + +## Kubernetes Secrets Store CSI Driver + +Secrets Store CSI driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a [Container Storage Interface (CSI)](https://kubernetes-csi.github.io/docs/) volume. + +The Secrets Store CSI driver `secrets-store.csi.k8s.io` allows Kubernetes to mount multiple secrets, keys, and certs stored in enterprise-grade external secrets stores into their pods as a volume. Once the Volume is attached, the data in it is mounted into the container’s file system. + +![Secrets-store CSI architecture](/docs/v2025.11.21/guides/secret-engines/csi_architecture.svg) + +When the `Pod` is created through the K8s API, it’s scheduled on to a node. The `kubelet` process on the node looks at the pod spec & see if there's any `volumeMount` request. The `kubelet` issues an `RPC` to the `CSI driver` to mount the volume. The `CSI driver` creates & mounts `tmpfs` into the pod. Then the `CSI driver` issues a request to the `Provider`. The provider talks to the external secrets store to fetch the secrets & write them to the pod volume as files. At this point, volume is successfully mounted & the pod starts running. + +You can read more about the Kubernetes Secrets Store CSI Driver [here](https://secrets-store-csi-driver.sigs.k8s.io/). + +## Consuming Secrets + +At first, you need to have a Kubernetes 1.16 or later cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). To check the version of your cluster, run: + +```bash +$ kubectl version --short +Client Version: v1.24.0 +Kustomize Version: v4.5.4 +Server Version: v1.23.13 +``` + +Before you begin: + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). +- Install Secrets Store CSI driver for Kubernetes secrets in your cluster from [here](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html). +- Install Vault Specific CSI provider from [here](https://github.com/hashicorp/vault-csi-provider) + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial stored in [examples](/docs/v2025.11.21/examples/guides/secret-engines/redis) folder in GitHub repository [KubeVault/docs](https://github.com/kubevault/kubevault) + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. To create a Redis Secret Engine, VaultServer version needs to be 1.12.1+. + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. And we also have the service account that the Vault server can authenticate. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2022-12-27T09:37:31Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha2 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: e32d10cd-aec9-4060-bc9a-098d69bb5d6b + resourceVersion: "294415" + uid: 09011421-5a2f-44cf-a8ac-7069565b0f78 +spec: + appRef: + apiGroup: kubevault.com + kind: VaultServer + name: vault + namespace: demo + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + backend: raft + backupTokenSecretRef: + name: vault-backup-token + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + stash: + addon: + backupTask: + name: vault-backup-1.10.3 + params: + - name: keyPrefix + value: k8s.kubevault.com.demo.vault + restoreTask: + name: vault-restore-1.10.3 + params: + - name: keyPrefix + value: k8s.kubevault.com.demo.vault + unsealer: + mode: + kubernetesSecret: + secretName: vault-keys + secretShares: 5 + secretThreshold: 3 + vaultRole: vault-policy-controller +``` + +## Enable & Configure REdis SecretEngine + +### Enable Redis SecretEngine + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/redis/secretengine.yaml +secretengine.engine.kubevault.com/redis-secret-engine created +``` + +### Create RedisRole + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/redis/secretenginerole.yaml +redisrole.engine.kubevault.com/write-read-role created +``` + +Let's say pod's service account name is `test-user-account` located in `demo` namespace. We need to create a [VaultPolicy](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) and a [VaultPolicyBinding](/docs/v2025.11.21/concepts/policy-crds/vaultpolicybinding) so that the pod has access to read secrets from the Vault server. + +### Create Service Account for Pod + +Let's create the service account `test-user-account` which will be used in VaultPolicyBinding. +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-user-account + namespace: demo +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/redis/serviceaccount.yaml +serviceaccount/test-user-account created + +$ kubectl get serviceaccount -n demo +NAME SECRETS AGE +test-user-account 1 4h10m +``` + +### Create SecretRoleBinding for Pod's Service Account + +SecretRoleBinding will create VaultPolicy and VaultPolicyBinding inside vault. +When a VaultPolicyBinding object is created, the KubeVault operator create an auth role in the Vault server. The role name is generated by the following naming format: `k8s.(clusterName or -).namespace.name`. Here, it is `k8s.kubevault.com.demo.write-read-role`. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretRoleBinding +metadata: + name: secret-role-binding + namespace: demo +spec: + roles: + - kind: RedisRole + name: write-read-role + subjects: + - kind: ServiceAccount + name: test-user-account + namespace: demo +``` + +Let's create SecretRoleBinding: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/redis/secret-role-binding.yaml +secretrolebinding.engine.kubevault.com/secret-role-binding created +``` +Check if the VaultPolicy and the VaultPolicyBinding are successfully registered to the Vault server: + +```bash +$ kubectl get vaultpolicy -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 8s + +$ kubectl get vaultpolicybinding -n demo +NAME STATUS AGE +srb-demo-secret-role-binding Success 10s +``` + +## Mount secrets into a Kubernetes pod + +So, we can create `SecretProviderClass` now. You can read more about `SecretProviderClass` [here](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#secretproviderclass). + +### Create SecretProviderClass + +Get `roleName` from VaultPolicyBinding +```bash +$ kubectl get vaultpolicybinding -n demo srb-demo-secret-role-binding -o=jsonpath="{['spec.vaultRoleName']}" +k8s.kubevault.com.demo.srb-demo-secret-role-binding +``` + +The `secretPath` can be constructed as `your-data-base-path/creds/your-role-name`. +Or get secretPath from VaultPolicy +```bash +$ kubectl get vaultpolicy -n demo srb-demo-secret-role-binding -o=jsonpath="{['spec.policyDocument']}" +path "/k8s.kubevault.com.redis.demo.redis-secret-engine/creds/k8s.kubevault.com.demo.write-read-role" { + capabilities = ["read"] +} +``` + +The secretPath here is `/k8s.kubevault.com.redis.demo.redis-secret-engine/creds/k8s.kubevault.com.demo.write-read-role` + +Create `SecretProviderClass` object with the following content: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: vault-db-provider + namespace: demo +spec: + provider: vault + parameters: + vaultAddress: "http://vault.demo:8200" + roleName: k8s.kubevault.com.demo.srb-demo-secret-role-binding + objects: | + - objectName: "redis-creds-username" + secretPath: "/k8s.kubevault.com.redis.demo.redis-secret-engine/creds/k8s.kubevault.com.demo.write-read-role" + secretKey: "username" + - objectName: "redis-creds-password" + secretPath: "/k8s.kubevault.com.redis.demo.redis-secret-engine/creds/k8s.kubevault.com.demo.write-read-role" + secretKey: "password" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/redis/secretproviderclass.yaml +secretproviderclass.secrets-store.csi.x-k8s.io/vault-db-provider created +``` + +NOTE: The `SecretProviderClass` needs to be created in the same namespace as the pod. + +### Create Pod + +Now we can create a `Pod` to consume the `Redis` secrets. When the `Pod` is created, the `Provider` fetches the secret and writes them to Pod's volume as files. At this point, the volume is successfully mounted and the `Pod` starts running. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: demo-app + namespace: demo +spec: + serviceAccountName: test-user-account + containers: + - image: jweissig/app:0.0.1 + name: demo-app + imagePullPolicy: Always + volumeMounts: + - name: secrets-store-inline + mountPath: "/secrets-store/redis-creds" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-db-provider" +``` + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/redis/pod.yaml +pod/demo-app created +``` +## Test & Verify + +Check if the Pod is running successfully, by running: + +```bash +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +demo-app 1/1 Running 0 11s +``` + +### Verify Secret + +If the Pod is running successfully, then check inside the app container by running + +```bash +$ kubectl exec -it -n demo pod/demo-app -- /bin/sh +/ # ls /secrets-store/redis-creds +redis-creds-password redis-creds-username + +/ # cat /secrets-store/redis-creds/redis-creds-password +eEip9Orr-yFONjlRGntY + +/ # cat /secrets-store/redis-creds/redis-creds-username +V_KUBERNETES-DEMO-TEST-USER-ACCOUNT_K8S.KUBEVAULT.COM.DEMO.WRITE-READ-ROLE_764DXABBDPMUGZP9C6AB_1672/app + +/ # exit +``` + +So, we can see that the secret `db-username` and `db-password` is mounted into the pod, where the secret key is mounted as file and value is the content of that file. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted + +``` diff --git a/content/docs/v2025.11.21/guides/secret-engines/redis/overview.md b/content/docs/v2025.11.21/guides/secret-engines/redis/overview.md new file mode 100644 index 000000000..1d04db4ea --- /dev/null +++ b/content/docs/v2025.11.21/guides/secret-engines/redis/overview.md @@ -0,0 +1,382 @@ +--- +title: Manage Redis credentials using the KubeVault operator +menu: + docs_v2025.11.21: + identifier: overview-redis + name: Overview + parent: redis-secret-engines + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Manage Redis credentials using the KubeVault operator + +Redis is one of the supported plugins for the database secrets engine. This plugin generates database credentials dynamically based on configured roles for the Redis database. You can easily manage [Redis secret engine](https://www.vaultproject.io/docs/secrets/databases/redis.html) using the KubeVault operator. + +![Redis secret engine](/docs/v2025.11.21/images/guides/secret-engines/redis/redis_secret_engine_guide.svg) + +You need to be familiar with the following CRDs: + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) +- [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) +- [RedisRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/redis) + +## Before you begin + +- Install KubeVault operator in your cluster from [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +In this tutorial, we are going to create a [role](https://developer.hashicorp.com/vault/docs/secrets/databases/redis#setup) using Redis and issue credential using SecretAccessRequest. + +## Vault Server + +If you don't have a Vault Server, you can deploy it by using the KubeVault operator. To create a Redis Secret Engine, VaultServer version needs to be 1.12.1+ + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) + +The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. You need to configure both the Vault server and the cluster so that the KubeVault operator can communicate with your Vault server. + +- [Configure cluster and Vault server](/docs/v2025.11.21/guides/vault-server/external-vault-sever#configuration) + +Now, we have the [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) that contains connection and authentication information about the Vault server. + +```bash +$ kubectl get appbinding -n demo +NAME AGE +vault 50m + +$ kubectl get appbinding -n demo vault -o yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + creationTimestamp: "2021-08-16T08:23:38Z" + generation: 1 + labels: + app.kubernetes.io/instance: vault + app.kubernetes.io/managed-by: kubevault.com + app.kubernetes.io/name: vaultservers.kubevault.com + name: vault + namespace: demo + ownerReferences: + - apiVersion: kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: VaultServer + name: vault + uid: 6b405147-93da-41ff-aad3-29ae9f415d0a + resourceVersion: "602898" + uid: b54873fd-0f34-42f7-bdf3-4e667edb4659 +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: http + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + kubernetes: + serviceAccountName: vault + tokenReviewerServiceAccountName: vault-k8s-token-reviewer + usePodServiceAccountForCSIDriver: true + path: kubernetes + vaultRole: vault-policy-controller +``` + +## Enable and Configure Redis Secret Engine + +When a [SecretEngine](/docs/v2025.11.21/concepts/secret-engine-crds/secretengine) crd object is created, the KubeVault operator will enable a secret engine on specified path and configure the secret engine with given configurations. + +A sample SecretEngine object for the Redis secret engine: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretEngine +metadata: + name: redis-secret-engine + namespace: demo +spec: + vaultRef: + name: vault + namespace: demo + redis: + databaseRef: + name: redis-standalone + namespace: demo + pluginName: "redis-database-plugin" + +``` + +Let's deploy SecretEngine: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/redis/secretengine.yaml +secretengine.engine.kubevault.com/redis-secret-engine created +``` + +Wait till the status become `Success`: + +```bash +$ kubectl get secretengines -n demo +NAME STATUS AGE +redis-secret-engine Success 10s +``` + +Since the status is `Success`, the Redis secret engine is enabled and successfully configured. You can use `kubectl describe secretengine -n ` to check for error events, if any. + +## Create Redis Role + +By using [RedisRole](/docs/v2025.11.21/concepts/secret-engine-crds/database-secret-engine/redis), you can create a [role](https://developer.hashicorp.com/vault/docs/secrets/databases/redis#setup) on the Vault server in Kubernetes native way. + +A sample RedisRole object is given below: + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: RedisRole +metadata: + name: write-read-role + namespace: demo +spec: + secretEngineRef: + name: redis-secret-engine + creationStatements: + - '["~*", "+@read","+@write"]' + defaultTTL: 1h + maxTTL: 24h +``` + +Let's deploy RedisRole: + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/redis/secretenginerole.yaml +redisrole.engine.kubevault.com/write-read-role created + +$ kubectl get redisrole -n demo +NAME STATUS AGE +write-read-role Success 34m +``` + +You can also check from Vault that the role is created. +To resolve the naming conflict, name of the role in Vault will follow this format: `k8s.{clusterName}.{metadata.namespace}.{metadata.name}`. + +> Don't have Vault CLI? Download and configure it as described [here](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + +```bash +$ vault list k8s.kubevault.com.redis.demo.redis-secret-engine/roles +Keys +---- +k8s.kubevault.com.demo.write-read-role + +$ vault read k8s.kubevault.com.redis.demo.redis-secret-engine/roles/k8s.kubevault.com.demo.write-read-role +Key Value +--- ----- +creation_statements [["~*", "+@read","+@write"]] +credential_type password +db_name k8s.kubevault.com.demo.redis-standalone +default_ttl 1h +max_ttl 24h +renew_statements [] +revocation_statements [] +rollback_statements [] +``` + +If we delete the Redis, then the respective role will be deleted from the Vault. + +```bash +$ kubectl delete -n demo redisrole write-read-role +redisrole.engine.kubevault.com "write-read-role" deleted +``` + +Check from Vault whether the role exists: + +```bash +$ vault read k8s.kubevault.com.redis.demo.redis-secret-engine/roles/k8s.kubevault.com.demo.write-read-role +No value found at k8s.kubevault.com.redis.demo.redis-secret-engine/roles/k8s.kubevault.com.demo.write-read-role + +$ vault list k8s.kubevault.com.redis.demo.redis-secret-engine/roles +No value found at k8s.kubevault.com.redis.demo.redis-secret-engine/roles +``` + +## Generate Redis credentials + +Here, we are going to make a request to Vault for Redis credentials by creating `write-read-access-req` SecretAccessRequest in `demo` namespace. + +```yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + name: write-read-access-req + namespace: demo +spec: + roleRef: + kind: RedisRole + name: write-read-role + subjects: + - kind: ServiceAccount + name: write-read-user + namespace: demo + +``` + +Here, `spec.roleRef` is the reference of Redis against which credentials will be issued. `spec.subjects` is the reference to the object or user identities a role binding applies to it will have read access of the credential secret. + +Now, we are going to create SecretAccessRequest. + +```bash +$ kubectl apply -f docs/examples/guides/secret-engines/redis/redisaccessrequest.yaml +secretaccessrequest.engine.kubevault.com/write-read-access-req created + +$ kubectl get secretaccessrequest -n demo +NAME STATUS AGE +write-read-access-req WaitingForApproval 14s +``` + +Database credentials will not be issued until it is approved. The KubeVault operator will watch for the approval in the `status.conditions[].type` field of the request object. You can use [KubeVault CLI](https://github.com/kubevault/cli), a [kubectl plugin](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/), to approve or deny SecretAccessRequest. + +```bash +# using KubeVault CLI as kubectl plugin to approve request +$ kubectl vault approve secretaccessrequest write-read-access-req -n demo +secretaccessrequests write-read-access-req approved + +$ kubectl get secretaccessrequest -n demo write-read-access-req -o yaml +apiVersion: engine.kubevault.com/v1alpha1 +kind: SecretAccessRequest +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"engine.kubevault.com/v1alpha1","kind":"SecretAccessRequest","metadata":{"annotations":{},"name":"write-read-access-req","namespace":"demo"},"spec":{"roleRef":{"kind":"RedisRole","name":"write-read-role"},"subjects":[{"kind":"ServiceAccount","name":"write-read-user","namespace":"demo"}]}} + vaultservers.kubevault.com/name: vault + vaultservers.kubevault.com/namespace: demo + creationTimestamp: "2022-12-28T09:14:25Z" + finalizers: + - kubevault.com + generation: 1 + name: write-read-access-req + namespace: demo + resourceVersion: "341401" + uid: 0bf92c6a-fbbb-4600-8bc8-8bddbf2c34dd +spec: + roleRef: + kind: RedisRole + name: write-read-role + subjects: + - kind: ServiceAccount + name: write-read-user + namespace: demo +status: + conditions: + - lastTransitionTime: "2022-12-28T09:15:22Z" + message: 'This was approved by: kubectl vault approve secretaccessrequest' + observedGeneration: 1 + reason: KubectlApprove + status: "True" + type: Approved + - lastTransitionTime: "2022-12-28T09:15:22Z" + message: The requested credentials successfully issued. + observedGeneration: 1 + reason: SuccessfullyIssuedCredential + status: "True" + type: Available + lease: + duration: 1h0m0s + id: k8s.kubevault.com.redis.demo.redis-secret-engine/creds/k8s.kubevault.com.demo.write-read-role/mNeREfw0SJQBekA8ZkzJn2Tf + renewable: true + observedGeneration: 1 + phase: Approved + secret: + name: write-read-access-req-c9ttdf + namespace: demo +``` + +Once SecretAccessRequest is approved, the KubeVault operator will issue credentials from Vault and create a secret containing the credential. It will also create a role and rolebinding so that `spec.subjects` can access secret. You can view the information in the `status` field. + +```bash +$ kubectl get secretaccessrequest write-read-access-req -n demo -o json | jq '.status' +{ + "conditions": [ + { + "lastTransitionTime": "2022-12-28T09:15:22Z", + "message": "This was approved by: kubectl vault approve secretaccessrequest", + "observedGeneration": 1, + "reason": "KubectlApprove", + "status": "True", + "type": "Approved" + }, + { + "lastTransitionTime": "2022-12-28T09:15:22Z", + "message": "The requested credentials successfully issued.", + "observedGeneration": 1, + "reason": "SuccessfullyIssuedCredential", + "status": "True", + "type": "Available" + } + ], + "lease": { + "duration": "1h0m0s", + "id": "k8s.kubevault.com.redis.demo.redis-secret-engine/creds/k8s.kubevault.com.demo.write-read-role/mNeREfw0SJQBekA8ZkzJn2Tf", + "renewable": true + }, + "observedGeneration": 1, + "phase": "Approved", + "secret": { + "name": "write-read-access-req-c9ttdf", + "namespace": "demo" + } +} + +$ kubectl get secret -n demo +NAME TYPE DATA AGE +write-read-access-req-c9ttdf Opaque 2 2m3s + +$ kubectl get secret -n demo write-read-access-req-c9ttdf -o yaml +apiVersion: v1 +data: + password: MUtwT2YtV0lyZG1qSTJQUktwSFg= + username: Vl9LVUJFUk5FVEVTLURFTU8tVkFVTFRfSzhTLktVQkVWQVVMVC5DT00uREVNTy5XUklURS1SRUFELVJPTEVfQVlCVFBLTVhGUEdPM0tHR05NUjJfMTY3MjIxODkyMg== +kind: Secret +metadata: + creationTimestamp: "2022-12-28T09:15:22Z" + name: write-read-access-req-c9ttdf + namespace: demo + ownerReferences: + - apiVersion: engine.kubevault.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: SecretAccessRequest + name: write-read-access-req + uid: 0bf92c6a-fbbb-4600-8bc8-8bddbf2c34dd + resourceVersion: "341397" + uid: b038419d-59ff-4946-8ff3-1a04984d6f0f +type: Opaque +``` + +If SecretAccessRequest is deleted, then credential lease (if any) will be revoked. + +```bash +$ kubectl delete secretaccessrequest -n demo write-read-access-req +secretaccessrequest.engine.kubevault.com "write-read-access-req" deleted +``` + +If SecretAccessRequest is `Denied`, then the KubeVault operator will not issue any credential. + +```bash +$ kubectl vault deny secretaccessrequest write-read-access-req -n demo +secretaccessrequest.engine.kubevault.com "write-read-access-req" deleted +``` + +> Note: Once SecretAccessRequest is `Approved`, you cannot change `spec.roleRef` and `spec.subjects` field. diff --git a/content/docs/v2025.11.21/guides/vault-ops-request/_index.md b/content/docs/v2025.11.21/guides/vault-ops-request/_index.md new file mode 100644 index 000000000..6be31265f --- /dev/null +++ b/content/docs/v2025.11.21/guides/vault-ops-request/_index.md @@ -0,0 +1,17 @@ +--- +title: Vault Ops Request Guides | KubeVault +menu: + docs_v2025.11.21: + identifier: ops-request-guides + name: Vault Ops Request + parent: guides + weight: 10 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/vault-ops-request/overview.md b/content/docs/v2025.11.21/guides/vault-ops-request/overview.md new file mode 100644 index 000000000..2ed3553a9 --- /dev/null +++ b/content/docs/v2025.11.21/guides/vault-ops-request/overview.md @@ -0,0 +1,53 @@ +--- +title: Vault Ops Request Overview +menu: + docs_v2025.11.21: + identifier: overview-ops-request-guides + name: Overview + parent: ops-request-guides + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/README). + +# Reconfiguring TLS of VaultServer + +This guide will give an overview on how KubeVault Enterprise operator reconfigures TLS configuration i.e. add TLS, remove TLS, update issuer/cluster issuer or Certificates and rotate the certificates of a `VaultServer`. + +## Before You Begin + +- You should be familiar with the following `KubeVault` concepts: + - [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) + - [VaultOpsRequest](/docs/v2025.11.21/concepts/vault-ops-request/overview) + +## How Reconfiguring VaultServer TLS Configuration Process Works + +The Reconfiguring VaultServer TLS process consists of the following steps: + +1. At first, a user creates a `VaultServer` Custom Resource Object (CRO). + +2. `KubeVault` operator watches the `VaultServer` CRO. + +3. When the operator finds a `VaultServer` CR, it creates required number of `StatefulSets` and related necessary stuff like secrets, services, etc. + +4. Then, in order to reconfigure the TLS configuration of the `VaultServer` the user creates a `VaultOpsRequest` CR with desired information. + +5. `KubeVault` operator watches the `VaultOpsRequest` CR. + +6. When it finds a `VaultOpsRequest` CR, it pauses the `VaultServer` object which is referred from the `VaultOpsRequest`. So, the `KubeVault` operator doesn't perform any operations on the `VaultServer` object during the reconfiguring TLS process. + +7. Then the `KubeVault` operator will add, remove, update or rotate TLS configuration based on the Ops Request yaml. + +8. Then the `KubeVault` operator will restart all the Pods of the database so that they restart with the new TLS configuration defined in the `VaultOpsRequest` CR. + +9. After the successful reconfiguring of the `VaultServer` TLS, the `KubeVault` operator resumes the `VaultServer` object so that the `KubeVault` Community operator resumes its usual operations. + +In the next docs, we are going to show a step by step guide on reconfiguring TLS configuration of a VaultServer using `VaultOpsRequest` CRD. \ No newline at end of file diff --git a/content/docs/v2025.11.21/guides/vault-ops-request/reconfigure_tls.md b/content/docs/v2025.11.21/guides/vault-ops-request/reconfigure_tls.md new file mode 100644 index 000000000..8170e850b --- /dev/null +++ b/content/docs/v2025.11.21/guides/vault-ops-request/reconfigure_tls.md @@ -0,0 +1,416 @@ +--- +title: Vault Ops Request Reconfigure TLS +menu: + docs_v2025.11.21: + identifier: reconfigure-tls-ops-request-guides + name: Reconfigure TLS + parent: ops-request-guides + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/README). + +# Reconfigure VaultServer TLS/SSL + +`KubeVault` supports reconfigure i.e. add, remove, update and rotation of TLS/SSL certificates for existing `VaultServer` via a `VaultOpsRequest`. This tutorial will show you how to use `KubeVault` to reconfigure TLS/SSL encryption. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). + +- Install [`cert-manger`](https://cert-manager.io/docs/installation/) v1.0.0 or later to your cluster to manage your SSL/TLS certificates. + +- Now, install KubeVault cli on your workstation and KubeVault operator in your cluster following the steps [here](/docs/v2025.11.21/setup/README). + +- To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial are stored in [docs/examples/guides/vault-ops-request](https://github.com/kubevault/kubevault/tree/{{< param "info.version" >}}/docs/examples/guides/vault-ops-request) folder in GitHub repository [kubevault/kubevault](https://github.com/kubevault/kubevault). + +## Add TLS to a VaultServer + +Here, We are going to create a `VaultServer` without TLS and then reconfigure the `VaultServer` to use TLS. + +### Deploy VaultServer without TLS + +In this section, we are going to deploy a VaultServer without TLS. In the next few sections we will reconfigure TLS using `VaultOpsRequest` CRD. Below is the YAML of the `VaultServer` CR that we are going to create, + +```yaml +apiVersion: kubevault.com/v1alpha2 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.10.3 + replicas: 3 + allowedSecretEngines: + namespaces: + from: All + secretEngines: + - gcp + backend: + raft: + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 5 + secretThreshold: 3 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: WipeOut + +``` + +Let's create the `VaultServer` CR we have shown above, + +```bash +$ kubectl create -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/vault-ops-request/vaultserver.yaml +vaultserver.kubevault.com/vault created +``` + + +Now, wait until `VaultServer` has status `Ready`. i.e, + +```bash +$ kubectl get vs -n demo +NAME REPLICAS VERSION STATUS AGE +vault 3 1.12.1 Ready 128m +``` + +### Create Issuer/ ClusterIssuer + +Now, We are going to create an example `Issuer` that will be used to enable SSL/TLS in VaultServer. Alternatively, you can follow this [cert-manager tutorial](https://cert-manager.io/docs/configuration/ca/) to create your own `Issuer`. + +- Start off by generating a ca certificates using openssl. + +```bash +$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./ca.key -out ./ca.crt -subj "/CN=vault/O=kubevault" +Generating a RSA private key +................+++++ +........................+++++ +writing new private key to './ca.key' +----- +``` + +- Now we are going to create a ca-secret using the certificate files that we have just generated. + +```bash +$ kubectl create secret tls vault-ca --cert=ca.crt --key=ca.key --namespace=demo + +secret/vault-ca created +``` + +Now, Let's create an `Issuer` using the `vault-ca` secret that we have just created. The `YAML` file looks like this: + +```yaml +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: issuer + namespace: demo +spec: + ca: + secretName: vault-ca +``` + +Let's apply the `YAML` file: + +```bash +$ kubectl create -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/vault-ops-request/issuer.yaml +issuer.cert-manager.io/issuer created +``` + +### Create VaultOpsRequest + +In order to add TLS to the VaultServer, we have to create a `VaultOpsRequest` CRO with our created issuer. Below is the YAML of the `VaultOpsRequest` CRO that we are going to create, + +```yaml +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: vault-ops-add-tls + namespace: demo +spec: + type: ReconfigureTLS + vaultRef: + name: vault + tls: + issuerRef: + name: issuer + kind: Issuer + apiGroup: "cert-manager.io" + certificates: + - alias: client + subject: + organizations: + - appscode + organizationalUnits: + - client +``` + +Here, + +- `spec.vaultRef.name` specifies that we are performing reconfigure TLS operation on `vault` VaultServer. +- `spec.type` specifies that we are performing `ReconfigureTLS` on our VaultServer. +- `spec.tls.issuerRef` specifies the issuer name, kind and api group. +- `spec.tls.certificates` specifies the certificates. + +Let's create the `VaultOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/vault-ops-request/vault-ops-add-tls.yaml +vaultopsrequest.ops.kubevault.com/vault-ops-add-tls created +``` + +#### Verify TLS Enabled Successfully + +Let's wait for `VaultOpsRequest` to be `Successful`. Run the following command to watch `VaultOpsRequest` CRO, + +```bash +$ kubectl get vaultopsrequest -n demo +Every 2.0s: kubectl get vaultopsrequest -n demo +NAME TYPE STATUS AGE +vault-ops-add-tls ReconfigureTLS Successful 91s +``` + +## Rotate Certificate + +Now we are going to rotate the certificate of this VaultServer. First let's check the current expiration date of the certificate. + +```bash +$ kubectl exec -it -n demo vault-0 -- bin/sh +/ # cd etc/vault/tls/server +/etc/vault/tls/server # cat tls.crt +-----BEGIN CERTIFICATE----- +MIID2DCCAsCgAwIBAgIQL1rqn4OHpvchiFRI3DPXIjANBgkqhkiG9w0BAQsFADAk +... +XJRRwl5psqcyp5ZJI1ar5JP1JCGQa3QTArwstw== +-----END CERTIFICATE----- +``` + +Copy & paste the certificate in any certificates decoding tool like [certlogic](https://certlogik.com/decoder/) & check it's expiry date. + +### Create VaultOpsRequest + +Now we are going to increase it using a VaultOpsRequest. Below is the yaml of the ops request that we are going to create, + +```yaml +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: vault-ops-rotate + namespace: demo +spec: + type: ReconfigureTLS + vaultRef: + name: vault + tls: + rotateCertificates: true +``` + +Here, + +- `spec.vaultRef.name` specifies that we are performing reconfigure TLS operation on `vault` VaultServer. +- `spec.type` specifies that we are performing `ReconfigureTLS` on our VaultServer. +- `spec.tls.rotateCertificates` specifies that we want to rotate the certificate of this VaultServer. + +Let's create the `VaultOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/vault-ops-request/vault-ops-rotate.yaml +vaultopsrequest.ops.kubevault.com/vault-ops-rotate created +``` + +#### Verify Certificate Rotated Successfully + +Let's wait for `VaultOpsRequest` to be `Successful`. Run the following command to watch `VaultOpsRequest` CRO, + +```bash +$ kubectl get vaultopsrequest -n demo +Every 2.0s: kubectl get vaultopsrequest -n demo +NAME TYPE STATUS AGE +vault-ops-rotate ReconfigureTLS Successful 112 +``` + +Now, let's check the expiration date of the certificate again, it should be updated. + +```bash +$ kubectl exec -it -n demo vault-0 -- bin/sh +/ # cd etc/vault/tls/server +/etc/vault/tls/server # cat tls.crt +-----BEGIN CERTIFICATE----- +MIID2DCCAsCgAwIBAgIQL1rqn4OHpvchiFRI3DPXIjANBgkqhkiG9w0BAQsFADAk +... +XJRRwl5psqcyp5ZJI1ar5JP1JCGQa3QTArwstw== +-----END CERTIFICATE----- +``` + +## Change Issuer/ClusterIssuer + +Now, we are going to change the issuer of this VaultServer. + +- Let's create a new ca certificate and key using a different subject `CN=ca-updated,O=kubevault-updated`. + +```bash +$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./ca.key -out ./ca.crt -subj "/CN=ca-updated/O=kubevault-updated" +Generating a RSA private key +..............................................................+++++ +......................................................................................+++++ +writing new private key to './ca.key' +----- +``` + +- Now we are going to create a new ca-secret using the certificate files that we have just generated. + +```bash +$ kubectl create secret tls vault-new-ca \ + --cert=ca.crt \ + --key=ca.key \ + --namespace=demo +secret/vault-new-ca created +``` + +Now, Let's create a new `Issuer` using the `vault-new-ca` secret that we have just created. The `YAML` file looks like this: + +```yaml +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: new-issuer + namespace: demo +spec: + ca: + secretName: vault-new-ca +``` + +Let's apply the `YAML` file: + +```bash +$ kubectl create -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/vault-ops-request/new-issuer.yaml +issuer.cert-manager.io/new-issuer created +``` + + +### Create VaultOpsRequest + +In order to use the new issuer to issue new certificates, we have to create a `VaultOpsRequest` CRO with the newly created issuer. Below is the YAML of the `VaultOpsRequest` CRO that we are going to create, + +```yaml +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: vault-ops-change-issuer + namespace: demo +spec: + type: ReconfigureTLS + vaultRef: + name: vault + tls: + issuerRef: + name: new-issuer + kind: Issuer + apiGroup: "cert-manager.io" +``` + +Here, + +- `spec.vaultRef.name` specifies that we are performing reconfigure TLS operation on `vault` VaultServer. +- `spec.type` specifies that we are performing `ReconfigureTLS` on our VaultServer. +- `spec.tls.issuerRef` specifies the issuer name, kind and api group. + +Let's create the `VaultOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/vault-ops-request/vault-ops-change-issuer.yaml +vaultopsrequest.ops.kubevault.com/vault-ops-change-issuer created +``` + +#### Verify Issuer is changed successfully + +Let's wait for `VaultOpsRequest` to be `Successful`. Run the following command to watch `VaultOpsRequest` CRO, + +```bash +$ kubectl get vaultopsrequest -n demo +Every 2.0s: kubectl get vaultopsrequest -n demo +NAME TYPE STATUS AGE +vault-ops-change-issuer ReconfigureTLS Successful 105s +``` + +## Remove TLS from the VaultServer + +Now, we are going to remove TLS from this VaultServer using a VaultOpsRequest. + +### Create VaultOpsRequest + +Below is the YAML of the `VaultOpsRequest` CRO that we are going to create, + +```yaml +apiVersion: ops.kubevault.com/v1alpha1 +kind: VaultOpsRequest +metadata: + name: vault-ops-remove + namespace: demo +spec: + type: ReconfigureTLS + vaultRef: + name: vault + tls: + remove: true +``` + +Here, + +- `spec.vaultRef.name` specifies that we are performing reconfigure TLS operation on `vault` VaultServer. +- `spec.type` specifies that we are performing `ReconfigureTLS` on our VaultServer. +- `spec.tls.remove` specifies that we want to remove tls from this VaultServer. + +Let's create the `VaultOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/vault-ops-request/vault-ops-remove.yaml +vaultopsrequest.ops.kubeavult.com/vault-ops-remove created +``` + +#### Verify TLS Removed Successfully + +Let's wait for `VaultOpsRequest` to be `Successful`. Run the following command to watch `VaultOpsRequest` CRO, + +```bash +$ kubectl get vaultopsrequest -n demo +Every 2.0s: kubectl get vaultopsrequest -n demo +NAME TYPE STATUS AGE +vault-ops-remove ReconfigureTLS Successful 105s +``` + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +kubectl delete vaultserver -n demo vault +kubectl delete issuer -n demo issuer new-issuer +kubectl delete vaultopsrequest vault-ops-add-tls vault-ops-remove vault-ops-rotate vault-ops-change-issuer +kubectl delete ns demo +``` diff --git a/content/docs/v2025.11.21/guides/vault-server/_index.md b/content/docs/v2025.11.21/guides/vault-server/_index.md new file mode 100755 index 000000000..b3028af15 --- /dev/null +++ b/content/docs/v2025.11.21/guides/vault-server/_index.md @@ -0,0 +1,17 @@ +--- +title: Vault Server Guides | KubeVault +menu: + docs_v2025.11.21: + identifier: vault-server-guides + name: Vault Server + parent: guides + weight: 10 +menu_name: docs_v2025.11.21 +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + diff --git a/content/docs/v2025.11.21/guides/vault-server/auth-method.md b/content/docs/v2025.11.21/guides/vault-server/auth-method.md new file mode 100644 index 000000000..a8ec251ac --- /dev/null +++ b/content/docs/v2025.11.21/guides/vault-server/auth-method.md @@ -0,0 +1,225 @@ +--- +title: Auth Method +menu: + docs_v2025.11.21: + identifier: auth-method + name: Auth Method + parent: vault-server-guides + weight: 20 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +In this tutorial, we'll see how we can enable, configure `JWT/OIDC` auth method & use it to authenticate to `VaultServer` using `KubeVault`. + +> Before jumping in, an `OIDC Provider` must be configured. An `Auth0` application has already been configured for this tutorial purpose. Application `Domain`, `Client ID`, `Client Secret`, `Allowed Callback URLs`, etc. must be properly set from the provider side. + +## Deploy VaultServer, Enable & Configure Auth Methods + +Let's start by deploying the `VaultServer`. We're going to enable & configure `JWT` auth method in this tutorial. + +Here's the complete `VaultServer` yaml: + +```yaml +apiVersion: kubevault.com/v1alpha2 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + version: 1.10.3 + replicas: 2 + allowedSecretEngines: + namespaces: + from: All + secretEngines: + - gcp + authMethods: + - type: jwt + path: jwt + jwtConfig: + defaultLeaseTTL: 1h + defaultRole: k8s.kubevault.com.demo.reader-writer-role + oidcClientID: aFSrk3w06WsQqyjA30HvhbbJIR1VBidU + oidcDiscoveryURL: https://dev-tob49v6v.us.auth0.com/ + credentialSecretRef: + name: jwt-cred + backend: + raft: + storage: + storageClassName: "standard" + resources: + requests: + storage: 1Gi + unsealer: + secretShares: 3 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys + monitor: + agent: prometheus.io + prometheus: + exporter: + resources: {} + terminationPolicy: WipeOut + +``` + +Let's focus on the `.spec.authMethods` section here: + +```yaml +authMethods: + - type: jwt + path: jwt + jwtConfig: + defaultLeaseTTL: 1h + defaultRole: k8s.kubevault.com.demo.reader-writer-role + oidcClientID: aFSrk3w06WsQqyjA30HvhbbJIR1VBidU + oidcDiscoveryURL: https://dev-tob49v6v.us.auth0.com/ + credentialSecretRef: + name: jwt-cred + +``` + +* `.spec.authMethods.type` is a required field, the type of authentication method we want to enable. +* `.spec.authMethods.path` is a required field, the path where we want to enable this authentication method. +* `.spec.authMethods.jwtConfig` contains various configuration for this authentication method. Details about configuration `parameters` can be found here: [JWT/OIDC Configuration](https://www.vaultproject.io/api-docs/auth/jwt#configure). + +In the `.spec.authMethods.jwtConfig` section, we've provided the necessary configuration details. A `K8s Secret` `jwt-cred` containing the provider `Client Secret` needs to be created before deploying the `VaultServer`, which is referred in the `.credentialSecretRef` section. + +Here's the `Secret` yaml: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: jwt-cred + namespace: demo +stringData: + oidc_client_secret: + +``` + +### Deploy the VaultServer + +Let's create the `Secret` first: +```bash +$ kubectl apply -f jwt-cred.yaml +secret/jwt-cred created +``` + +Let's deploy the `VaultServer` now: +```bash +$ kubectl apply -f vaultserver.yaml +vaultserver.kubevault.com/vault created +``` + +Upon successful deployment of `VaultServer`, the defined `authMethods` will be enabled & configured by the provider configuration. `KubeVault` operator will also create the necessary policies required for the auth methods. + +We can verify it using the `Vault CLI`: + +```bash +$ vault auth list + +Path Type Accessor Description +---- ---- -------- ----------- +jwt/ jwt auth_jwt_ba23cc30 n/a +kubernetes/ kubernetes auth_kubernetes_40fd86fd n/a +token/ token auth_token_950c8b80 token based credentials +``` + +```bash +$ vault read auth/jwt/config + +Key Value +--- ----- +bound_issuer n/a +default_role k8s.kubevault.com.demo.reader-writer-role +jwks_ca_pem n/a +jwks_url n/a +jwt_supported_algs [] +jwt_validation_pubkeys [] +namespace_in_state true +oidc_client_id aFSrk3w06WsQqyjA30HvhbbJIR1VBidU +oidc_discovery_ca_pem n/a +oidc_discovery_url https://dev-tob49v6v.us.auth0.com/ +oidc_response_mode n/a +oidc_response_types [] +provider_config map[] + +``` +### Create VaultPolicy & VaultPolicyBinding + +So, we're now ready to create `VaultPolicy` & `VaultPolicyBinding`. We'll create a simple `KV` policy to enable user with `read` & `list` privileges only. + +Here's the `VaultPolicy` yaml that we're going to create: + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: reader-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "/kv/*" { + capabilities = ["read", "list"] + } + +``` + +Let's create the `VaultPolicy`: + +```bash +$ kubectl apply -f policy.yaml +vaultpolicy.policy.kubevault.com/reader-policy created +``` + +Here's the `VaultPolicyBinding` yaml that we're going to create. Notice that, in the `.spec.subjectRef` section we're using the jwt method which is already enabled. + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicyBinding +metadata: + name: reader-role + namespace: demo +spec: + vaultRef: + name: vault + policies: + - ref: reader-policy + subjectRef: + jwt: + path: jwt + boundAudiences: + - "aFSrk3w06WsQqyjA30HvhbbJIR1VBidU" + allowedRedirectUris: + - "http://localhost:8200/ui/vault/auth/jwt/oidc/callback" + - "http://localhost:8250/oidc/callback" + userClaim: "sub" + +``` + +Let's create the `VaultPolicyBinding`: + +```bash +$ kubectl apply -f policybinding.yaml +vaultpolicybinding.policy.kubevault.com/reader-role created +``` + +When a `VaultPolicyBinding` is created, `KubeVault` will create a role which can be used to Login to the `Vault`. A Vault role `vaultRoleName: k8s.kubevault.com.demo.reader-role` will be created in our case. + +Now, we can port-forward from `Vault` & Login using the `Vault UI` with this role & the authentication method. + +![Login](/docs/v2025.11.21/images/guides/vault-server/vault-login.jpg) diff --git a/content/docs/v2025.11.21/guides/vault-server/external-vault-sever.md b/content/docs/v2025.11.21/guides/vault-server/external-vault-sever.md new file mode 100644 index 000000000..d9572f4cc --- /dev/null +++ b/content/docs/v2025.11.21/guides/vault-server/external-vault-sever.md @@ -0,0 +1,326 @@ +--- +title: External Vault Server +menu: + docs_v2025.11.21: + identifier: external-vault-server + name: External Vault Server + parent: vault-server-guides + weight: 30 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# External Vault Server + +In this tutorial, we are going to demonstrate how the KubeVault operator works with external Vault servers (i.e. not provisioned by the KubeVault operator). To do so, we need to configure both the cluster and the Vault server. +Later we will create a [Vault policy](https://www.vaultproject.io/docs/concepts/policies.html) +using [VaultPolicy CRD](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) in Vault to check whether it is working or not. + +## Before you begin + +- Install KubeVault operator in your cluster following the steps [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +## Configuration + +To communicate with Vault, the KubeVault operator needs to perform authentication to Vault sever. +The Vault server will issue a `token` in the response of successful authentication. +Then the KubeVault operator will perform the rest of the tasks using that `token`. +Hence, the `token` must have the path-permissions that we want to access from KubeVault operator over API call. + +We will use [Kubernetes auth method](https://www.vaultproject.io/docs/auth/kubernetes.html) throughout the tutorial, +you can use any from the below list: + +- [AWS IAM Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/aws-iam) +- [Kubernetes Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/kubernetes) +- [TLS Certificates Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/tls) +- [Token Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/token) +- [Userpass Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/userpass) +- [GCP IAM Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/gcp-iam) +- [Azure Auth Method](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/azure) + +The whole configuration process can be divided into two parts: + +- `Cluster configuration`: Create an [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) which holds + connection and authentication information of Vault. Also create necessary Kubernetes resources (i.e. `secret`, `service account`, `ClusterRole`, `ClusterRoleBinding`, etc.) based on the requirements of the AppBinding. + +- `Vault configuration`: Enable and Configure the auth method in Vault. Create [Vault policy](https://www.vaultproject.io/docs/concepts/policies.html) with necessary path-permissions which will be required by the KubeVault operator. Create a `user` or a `role` under the auth method mentioning the vault policies. This role name will be referenced by the AppBinding while performing authentication to Vault and the Vault will issue `token` in the response of successful authentication with assigned policies. + +### Cluster Configuration + +Since we are using the Kubernetes auth method, we need to create two Kubernetes `service accounts`. +One of them will be used by the Vault to verify Kubernetes authentication. The other one will be used by the AppBinding +to perform authentication to Vault. + +#### Create Token Reviewer Service Account + +The [Kubernetes auth method](https://www.vaultproject.io/docs/auth/kubernetes.html) can be used to authenticate with Vault using a Kubernetes Service Account Token. This auth method accesses the Kubernetes `TokenReview API` to validate the provided JWT is still valid. The service account used in this auth method will need to have access to the `TokenReview API`. If Kubernetes is configured to use RBAC roles, the Service Account should be granted permission to access this API. + +Let's name token reviewer service account as `token-reviewer` and create it: + +```bash +$ kubectl create serviceaccount -n demo token-reviewer +serviceaccount/token-reviewer created +``` + +`ClusterRoleBinding` for the token reviewer service account: + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: role-tokenreview-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: token-reviewer + namespace: demo +``` + +Create `ClusterRoleBinding`: + +```bash +$ kubectl apply -f docs/examples/guides/vault-server/clusterRoleBinding.yaml +clusterrolebinding.rbac.authorization.k8s.io/role-tokenreview-binding created +``` + +Get the service account JWT token which will be used while configuring Vault: + +```bash +$ kubectl get secrets -n demo token-reviewer-token-s9hrs -o=jsonpath='{.data.token}' | base64 -d +eyJhbGciOiJSUzI1NiIsImtp... +``` + +#### Create AppBinding Service Account + +The KubeVault operator will use the AppBinding that holds a reference to this service account to +perform authentication. + +Let's name the service account `vault` and create it: + +```bash +$ kubectl create serviceaccount -n demo vault +serviceaccount/vault created +``` + +#### Create AppBinding + +The [AppBinding CRD](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) provides a way to specify connection information, credential and +parameters that are necessary for communicating with Vault. + +Access vault server using `url`: + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: vault + namespace: demo +spec: + clientConfig: + url: https://demo-vault-server.com ## remote vault server url + caBundle: eyJtc2ciOiJleGFtcGxlIn0= ## base64 encoded vault server ca.crt + parameters: + apiVersion: config.kubevault.com/v1alpha1 + kind: VaultServerConfiguration + path: kubernetes ## Kubernetes auth is enabled in this path + vaultRole: vault-role ## auth-role name against which login will be done + kubernetes: + serviceAccountName: vault ## service account name + usePodServiceAccountForCSIDriver: true ## required while using CSI driver +``` + +Access vault server using Kubernetes service by replacing `spec.clientConfig`: + +```yaml +spec: + clientConfig: + service: + name: vault + port: 8200 + scheme: HTTPS + caBundle: eyJtc2ciOiJleGFtcGxlIn0= ## base64 encoded vault server ca.crt +``` + +Create AppBinding: + +```bash +$ kubectl apply -f docs/examples/guides/vault-server/appBinding.yaml +appbinding.appcatalog.appscode.com/vault created +``` + +### Vault Configuration + +We will use Vault CLI to configure Vault. + +1. Create [Vault policy](https://www.vaultproject.io/docs/concepts/policies.html) which contains a list of `path` along with + `capacities`. For more details visit Vault [official doc](https://www.vaultproject.io/docs/concepts/policies.html#creating-policies). + + Create `vault.hcl` file: + +```hcl + path "sys/mounts" { + capabilities = ["read", "list"] + } + path "sys/mounts/*" { + capabilities = ["create", "read", "update", "delete"] + } + path "sys/leases/revoke/*" { + capabilities = ["update"] + } + path "sys/policy/*" { + capabilities = ["create", "update", "read", "delete", "list"] + } + path "sys/policy" { + capabilities = ["read", "list"] + } + path "sys/policies" { + capabilities = ["read", "list"] + } + path "sys/policies/*" { + capabilities = ["create", "update", "read", "delete", "list"] + } + path "auth/kubernetes/role" { + capabilities = ["read", "list"] + } + path "auth/kubernetes/role/*" { + capabilities = ["create", "update", "read", "delete", "list"] + } +``` + + Create vault policy: + +```bash +$ vault policy write vault-policy examples/guides/vault-server/vault.hcl +Success! Uploaded policy: vault-policy +``` + + List policies to check: + +```bash +$ vault list sys/policy +Keys +---- +default +root +vault-policy +``` + +2. Enable and configure the Kubernetes auth method (if not already enabled). For more details visit Vault + [official doc](https://www.vaultproject.io/docs/auth/kubernetes.html#configuration). + + Enable Kubernetes auth: + +```bash +$ vault auth enable kubernetes +Success! Enabled kubernetes auth method at: kubernetes/ +``` + + Configure Kubernetes auth with `token-reviewer` service account JWT token: + +```bash +$ vault write auth/kubernetes/config \ + token_reviewer_jwt="eyJhbGciOiJSUzI1N..." \ + kubernetes_host=https://127.0.0.1:40969\ + kubernetes_ca_cert=@examples/guides/vault-server/ca.crt +Success! Data written to: auth/kubernetes/config +``` + + You can find `kubernetes_host` and `kubernetes_ca_cert` in your cluster's `kubeconfig` file. + +3. Create an auth method role which includes Vault policies. + The KubeVault operator will perform authentication under this role and will have permission + mentioned by the policies. + + Create Kubernetes auth method role: + +```bash +$ vault write auth/kubernetes/role/vault-role \ + bound_service_account_names=vault \ + bound_service_account_namespaces=demo \ + policies=vault-policy \ + ttl=1h +Success! Data written to: auth/kubernetes/role/vault-role +``` + +## Testing + +We will create a Vault policy using [VaultPolicy CRD](/docs/v2025.11.21/concepts/policy-crds/vaultpolicy) to check whether our configuration worked or not. + +Deploy `secret-policy.yaml`: + +```yaml +apiVersion: policy.kubevault.com/v1alpha1 +kind: VaultPolicy +metadata: + name: custom-policy + namespace: demo +spec: + vaultRef: + name: vault + policyDocument: | + path "sys/policy" { + capabilities = ["read", "list", "create", "update"] + } + + path "sys/policy/*" { + capabilities = ["read"] + } + +``` + +```bash +$ kubectl apply -f docs/examples/guides/vault-server/secret-policy.yaml +vaultpolicy.policy.kubevault.com/secret-admin created +``` + +Now you can check from Vault: + +```bash +$ vault list sys/policy +Keys +---- +default +root +secret-admin +vault-policy +``` + +So, we can see, `secret-admin` policy is already on the list. + +Now delete the VaultPolicy crd: + +```bash +$ kubectl delete vaultpolicy secret-admin -n demo +vaultpolicy.policy.kubevault.com "secret-admin" deleted +```` + +Deleting VaultPolicy crd will also delete the policy from Vault. + +Updated list: + +```bash +$ vault list sys/policy +Keys +---- +default +root +vault-policy +``` diff --git a/content/docs/v2025.11.21/guides/vault-server/overview.md b/content/docs/v2025.11.21/guides/vault-server/overview.md new file mode 100644 index 000000000..71426d584 --- /dev/null +++ b/content/docs/v2025.11.21/guides/vault-server/overview.md @@ -0,0 +1,51 @@ +--- +title: Vault Server Overview +menu: + docs_v2025.11.21: + identifier: overview-vault-server + name: Overview + parent: vault-server-guides + weight: 10 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Overview + +The KubeVault operator makes it easy to deploy, maintain and manage Vault servers in Kubernetes clusters. It covers automatic initialization and unsealing and also stores unseal keys and root token in a secure way. The KubeVault operator can manage policies and secret engines of Vault servers which are not provisioned by the KubeVault operator. It has the following features: + +- **Vault Policy Management**: Provides a Kubernetes native way to manage Vault policies and bind those policies to the users or the auth method roles. + + - [Vault Policy](/docs/v2025.11.21/guides/policy-management/overview#vaultpolicy) + - [Vault Policy Binding](/docs/v2025.11.21/guides/policy-management/overview#vaultpolicybinding) + +- **Vault Secret Engine Management**: Provides a Kubernetes native way to manage Vault secret engines. + + - [GCP Secret Engine](/docs/v2025.11.21/guides/secret-engines/gcp/overview) + - [AWS Secret Engine](/docs/v2025.11.21/guides/secret-engines/aws/overview) + - [Azure Secret Engine](/docs/v2025.11.21/guides/secret-engines/azure/overview) + - Database Secret Engine + - [MongoDB Secret Engine](/docs/v2025.11.21/guides/secret-engines/mongodb/overview) + - [MySQL Secret Engine](/docs/v2025.11.21/guides/secret-engines/mysql/overview) + - [PostgreSQL Secret Engine](/docs/v2025.11.21/guides/secret-engines/postgres/overview) + +## Setup Vault Server + +![Overview](/docs/v2025.11.21/images/guides/vault-server/overview_vault_server_guide.svg) + +Deploy Vault server using the KubeVault operator: + +- [Deploy Vault Server](/docs/v2025.11.21/guides/vault-server/vault-server) +- [Enable Vault CLI](/docs/v2025.11.21/guides/vault-server/vault-server#enable-vault-cli) + + Configure external Vault server so that the KubeVault operator can communicate with it: + +- [Configure Cluster and External Vault Server](/docs/v2025.11.21/guides/vault-server/external-vault-sever) diff --git a/content/docs/v2025.11.21/guides/vault-server/vault-server.md b/content/docs/v2025.11.21/guides/vault-server/vault-server.md new file mode 100644 index 000000000..b64188197 --- /dev/null +++ b/content/docs/v2025.11.21/guides/vault-server/vault-server.md @@ -0,0 +1,298 @@ +--- +title: Vault Server +menu: + docs_v2025.11.21: + identifier: vault-server + name: Vault Server + parent: vault-server-guides + weight: 20 +menu_name: docs_v2025.11.21 +section_menu_id: guides +info: + cli: v0.23.0 + installer: v2025.11.21 + operator: v0.23.0 + unsealer: v0.23.0 + version: v2025.11.21 +--- + +> New to KubeVault? Please start [here](/docs/v2025.11.21/concepts/README). + +# Vault Server + +You can easily deploy and manage [HashiCorp Vault](https://www.vaultproject.io/) in the Kubernetes cluster using KubeVault operator. In this tutorial, we are going to deploy Vault on the Kubernetes cluster using KubeVault operator. + +![Vault Server](/docs/v2025.11.21/images/guides/vault-server/vault_server_guide.svg) + +## Before you begin + +- Install KubeVault operator in your cluster following the steps [here](/docs/v2025.11.21/setup/README). + +To keep things isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +## Deploy Vault Server + +To start with this tutorial, you need to be familiar with the following CRDs: + +- [AppBinding](/docs/v2025.11.21/concepts/vault-server-crds/auth-methods/appbinding) +- [VaultServerVersion](/docs/v2025.11.21/concepts/vault-server-crds/vaultserverversion) +- [VaultServer](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) + +### Deploy VaultServerVersion + +By installing KubeVault operator, you have already deployed some VaultServerVersion crds named after +the Vault image tag its using. You can list them by using the following command: + +```bash +$ kubectl get vaultserverversions +NAME VERSION VAULT_IMAGE DEPRECATED AGE +0.11.5 0.11.5 vault:0.11.5 20h +1.10.3 1.10.3 vault:1.10.3 20h +1.11.5 1.11.5 vault:1.11.5 20h +1.12.1 1.12.1 vault:1.12.1 20h +1.2.0 1.2.0 vault:1.2.0 20h +1.2.2 1.2.2 vault:1.2.2 20h +1.2.3 1.2.3 vault:1.2.3 20h +1.5.9 1.5.9 vault:1.5.9 20h +1.6.5 1.6.5 vault:1.6.5 20h +1.7.2 1.7.2 vault:1.7.2 20h +1.7.3 1.7.3 vault:1.7.3 20h +1.8.2 1.8.2 vault:1.8.2 20h +1.9.2 1.9.2 vault:1.9.2 20h +``` + +Now you can use them or deploy your own version by yourself: + +```yaml +apiVersion: catalog.kubevault.com/v1alpha1 +kind: VaultServerVersion +metadata: + name: 1.10.3 +spec: + exporter: + image: kubevault/vault-exporter:v0.1.1 + unsealer: + image: kubevault/vault-unsealer:v0.8.0 + vault: + image: vault:1.10.3 + version: 1.10.3 +``` + +Deploy VaultServerVersion `1.10.3`: + +```bash +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/vault-server/vaultserverversion.yaml +vaultserverversion.catalog.kubevault.com/1.10.3 created +``` + +### Deploy VaultServer + +Once you have deployed VaultServerVersion, you are ready to deploy VaultServer. + +```yaml +apiVersion: kubevault.com/v1alpha2 +kind: VaultServer +metadata: + name: vault + namespace: demo +spec: + replicas: 1 + version: 1.10.3 + serviceTemplates: + - alias: vault + metadata: + annotations: + name: vault + spec: + type: NodePort + backend: + inmem: {} + unsealer: + secretShares: 4 + secretThreshold: 2 + mode: + kubernetesSecret: + secretName: vault-keys +``` + +Here we are using `inmem` backend which will lose data when Vault server pods are restarted. For production setup, use an appropriate backend. For more information about supported **backends** and **unsealer options** visit `VaultServer` CRD [documentation](/docs/v2025.11.21/concepts/vault-server-crds/vaultserver) + +Deploy `VaultServer`: + +```bash +$ kubectl apply -f https://github.com/kubevault/kubevault/raw/{{< param "info.version" >}}/docs/examples/guides/vault-server/vaultserver.yaml +vaultserver.kubevault.com/vault created +``` + +Check VaultServer status: + +```bash +$ kubectl get vaultserver -n demo +NAME NODES VERSION STATUS AGE +vault 1 1.10.3 Processing 47s +$ kubectl get vaultserver -n demo +NAME NODES VERSION STATUS AGE +vault 1 1.10.3 Sealed 54s +$ kubectl get vaultserver -n demo +NAME NODES VERSION STATUS AGE +vault 1 1.10.3 Running 68s +``` + +Since the status is `Running` that means you have deployed the Vault server successfully. Now, you are ready to use with this Vault server. + +On creation of `VaultServer` object, the KubeVault operator performs the following tasks: + +- Creates a `deployment` for Vault named after VaultServer crd + + ```bash + $ kubectl get deployment -n demo + NAME READY UP-TO-DATE AVAILABLE AGE + vault 1/1 1 1 25m + ``` + +- Creates a `service` to communicate with vault pod/pods + + ```bash + $ kubectl get services -n demo + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + vault NodePort 10.110.35.39 8200:32580/TCP,8201:30062/TCP 20m + ``` + +- Creates an `AppBinding` that holds connection information for this Vault server. + + ```bash + $ kubectl get appbindings -n demo + NAME AGE + vault 30m + ``` + +- Creates a `ServiceAccount` which will be used by the AppBinding for performing authentication. + + ```bash + $ kubectl get sa -n demo + NAME SECRETS AGE + vault 1 36m + ``` + +- Unseals Vault and stores the Vault root token. For `kubernetesSecret` mode, the operator creates a k8s secret containing root token. + + ```bash + $ kubectl get secrets -n demo + NAME TYPE DATA AGE + vault-keys Opaque 5 42m + ``` + +- Enables `Kubernetes auth method` and creates k8s auth role with Vault policies for the `service account`(here 'vault') on Vault. + +## Enable Vault CLI + +> Don't have the Vault binary? Download from [here](https://www.vaultproject.io/downloads.html). + +If you want to communicate with the Vault servers using [Vault (CLI)](https://www.vaultproject.io/docs/commands/), perform the following commands: + +Get your desire Vault server pod name: + +```bash +$ kubectl get pods -n demo -l=app.kubernetes.io/name=vault-operator +NAME READY STATUS RESTARTS AGE +vault-8679f4cbf-v78cs 3/3 Running 0 93m +``` + +Perform port-forwarding: + +```bash +$ kubectl port-forward -n demo pod/vault-8679f4cbf-v78cs 8200 +Forwarding from 127.0.0.1:8200 -> 8200 +Forwarding from [::1]:8200 -> 8200 +... +``` + +Now, you can access the Vault server at `https://localhost:8200`. + +Retrieve the Vault server CA certificate from the pod `spec` and save the value from `--vault.ca-cert` to a file named `ca.crt`. + +```bash +$ kubectl get pods vault-8679f4cbf-v78cs -n demo -o jsonpath='{.spec.containers[?(@.name=="vault-unsealer")].args}' +[run --v=3 --secret-shares=4 --secret-threshold=2 --vault.ca-cert=-----BEGIN CERTIFICATE----- +MIICuDCCAaCgAwIBAgIBADANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDEwJjYTAe +Fw0xOTExMDYwOTM2NDhaFw0yOTExMDMwOTM2NDhaMA0xCzAJBgNVBAMTAmNhMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3OfhIHN4VIidwXkf5RTMRl3J +I3+szklt6xw2ICX83OLFKk5N2DmVM1zCLcBBwE3b2PBnP3eDGEVadIHj14T+9xdc +zLjj8WbCjVR824Xn2oDLOIuwso4SFFLD1kgyfmrDw9fs0tzL8bAQqYF/75q2+Pu5 +ERVscb0wXwVTE6sEqNToWqG190aUEuLbLE0n2BwqGdX1xHDhe34YgjXwvssdUJS5 +tTG83iWsAJilyjFBl1Y5gP6hkgi1IB+R6HTyXY1rzKiNn3WVofp1kEeEMAJElC1Z +q4W087gYrl702MpCDh5OfVq+C4f2lc2BLh0HQ5FU1ksecFyvTo5ohdBaNzs20QID +AQABoyMwITAOBgNVHQ8BAf8EBAMCAqQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG +9w0BAQsFAAOCAQEAn6YSx7ndvmSU+SH0bFJjnLSGMSOwWtfRAiAnJ8z+0Oea87Rr +nM+fIR4QTW8bo55Q9+fQztoWvpsb9scwfF6dg92/CsMSiOhVFvJLHHASv0Oh6vC0 +dbC2N6ZGvMQb99ZPjpt5By5w7Gy5eZG2lBwitYW5M9imtxuAlkZyobrnXzNDCrYI +GDVcajcirb4qI36jjLBE9iYDiUfo3uPcgWO9XnDwRvM09lse2+VRttl7/2fqE7Vh +3mstGC4e50rgshrxvVBx6NFnTo41OpMnG7GUYCtn4/9/W5M0QDEs6rWENj6g064o +JfizhesI4ULH4XBLLJ0VN6Wp6QVJ5tEyxSA5MA== +-----END CERTIFICATE----- + --auth.k8s-host= ... ... ... +``` + +Get `vault-tls` from the Kubernetes secret and write it on `tls.crt` and `tls.key` respectively: + +```bash +$ kubectl get secrets -n demo vault-vault-tls -o jsonpath="{.data.tls\.crt}" | base64 -d>tls.crt + +$ kubectl get secrets -n demo vault-vault-tls -o jsonpath="{.data.tls\.key}" | base64 -d>tls.key +``` + +List files to check: + +```bash +$ ls +ca.crt tls.crt tls.key +``` + +Export Vault environment variables: + +```bash +$ export VAULT_ADDR=https://127.0.0.1:8200 + +$ export VAULT_TOKEN=$(kubectl get secrets -n demo vault-keys -o jsonpath="{.data.vault-root-token}" | base64 --decode; echo) + +$ export VAULT_CACERT=ca.crt # put ca.crt file directory + +$ export VAULT_CLIENT_CERT=tls.crt # put tls.crt file directory + +$ export VAULT_CLIENT_KEY=tls.key # put tls.key file directory + +``` + +Now check whether Vault server can be accessed: + +```bash +$ vault status +Key Value +--- ----- +Seal Type shamir +Initialized true +Sealed false +Total Shares 4 +Threshold 2 +Version 1.2.3 +Cluster Name vault-cluster-bb64ffd2 +Cluster ID 94fcaedb-0e10-8600-21f5-97339509c60b +HA Enabled false +``` + +```bash +$ vault list sys/policy +Keys +---- +default +k8s.-.demo.vault-auth-method-controller +root +vault-policy-controller +``` + +Vault CLI is ready to use. To learn more about the Vault CLI and its functionality, visit the [official documentation](https://www.vaultproject.io/docs/commands/). diff --git a/content/docs/v2025.11.21/images/concepts/architecture.svg b/content/docs/v2025.11.21/images/concepts/architecture.svg new file mode 100644 index 000000000..74622cbea --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/architecture.svg @@ -0,0 +1,632 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/concepts/aws_role.svg b/content/docs/v2025.11.21/images/concepts/aws_role.svg new file mode 100644 index 000000000..c4c4ae92b --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/aws_role.svg @@ -0,0 +1,324 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/concepts/azure_role.svg b/content/docs/v2025.11.21/images/concepts/azure_role.svg new file mode 100644 index 000000000..fd699c7c4 --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/azure_role.svg @@ -0,0 +1,323 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/concepts/backup.svg b/content/docs/v2025.11.21/images/concepts/backup.svg new file mode 100644 index 000000000..e42156e0c --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/backup.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + vault-backup-1.10.3 + Vault + + + + + vault-backup-1.10.3 + + \ No newline at end of file diff --git a/content/docs/v2025.11.21/images/concepts/elasticsearch_role.svg b/content/docs/v2025.11.21/images/concepts/elasticsearch_role.svg new file mode 100644 index 000000000..76b2513c0 --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/elasticsearch_role.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/docs/v2025.11.21/images/concepts/gcp_role.svg b/content/docs/v2025.11.21/images/concepts/gcp_role.svg new file mode 100644 index 000000000..cb270382c --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/gcp_role.svg @@ -0,0 +1,323 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/concepts/mariadb_role.svg b/content/docs/v2025.11.21/images/concepts/mariadb_role.svg new file mode 100644 index 000000000..9f3988498 --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/mariadb_role.svg @@ -0,0 +1,406 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/concepts/mongodb_role.svg b/content/docs/v2025.11.21/images/concepts/mongodb_role.svg new file mode 100644 index 000000000..9bce01196 --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/mongodb_role.svg @@ -0,0 +1,374 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/concepts/mysql_role.svg b/content/docs/v2025.11.21/images/concepts/mysql_role.svg new file mode 100644 index 000000000..0ab600cdd --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/mysql_role.svg @@ -0,0 +1,373 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/concepts/pki_role.svg b/content/docs/v2025.11.21/images/concepts/pki_role.svg new file mode 100644 index 000000000..57c7a15cc --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/pki_role.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/docs/v2025.11.21/images/concepts/postgres_role.svg b/content/docs/v2025.11.21/images/concepts/postgres_role.svg new file mode 100644 index 000000000..5d25f8496 --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/postgres_role.svg @@ -0,0 +1,373 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/concepts/redis_role.svg b/content/docs/v2025.11.21/images/concepts/redis_role.svg new file mode 100644 index 000000000..b3f221e68 --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/redis_role.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/docs/v2025.11.21/images/concepts/restore.svg b/content/docs/v2025.11.21/images/concepts/restore.svg new file mode 100644 index 000000000..c725d90a3 --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/restore.svg @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + vault-restore-1.10.3 + vault-restore-1.10.3 + Vault + + + + \ No newline at end of file diff --git a/content/docs/v2025.11.21/images/concepts/secret_access_request.svg b/content/docs/v2025.11.21/images/concepts/secret_access_request.svg new file mode 100644 index 000000000..b777beb8f --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/secret_access_request.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/docs/v2025.11.21/images/concepts/vault_policy.svg b/content/docs/v2025.11.21/images/concepts/vault_policy.svg new file mode 100644 index 000000000..61f24800d --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/vault_policy.svg @@ -0,0 +1,323 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/concepts/vault_policy_binding.svg b/content/docs/v2025.11.21/images/concepts/vault_policy_binding.svg new file mode 100644 index 000000000..6e858e686 --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/vault_policy_binding.svg @@ -0,0 +1,368 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/concepts/vault_server.svg b/content/docs/v2025.11.21/images/concepts/vault_server.svg new file mode 100644 index 000000000..f44ced3fe --- /dev/null +++ b/content/docs/v2025.11.21/images/concepts/vault_server.svg @@ -0,0 +1,762 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/csi-driver-policy-aws.jpg b/content/docs/v2025.11.21/images/csi-driver-policy-aws.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8aefa42936aab64d6cbe127e125e0823a3b6261e GIT binary patch literal 52367 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𝔷 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 RIR9wDGeuQ}yvMKJ{|~iGReS&d literal 0 HcmV?d00001 diff --git a/content/docs/v2025.11.21/images/guides/policy-management/vault_policy.svg b/content/docs/v2025.11.21/images/guides/policy-management/vault_policy.svg new file mode 100644 index 000000000..61f24800d --- /dev/null +++ b/content/docs/v2025.11.21/images/guides/policy-management/vault_policy.svg @@ -0,0 +1,323 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/guides/policy-management/vault_policy_binding.svg b/content/docs/v2025.11.21/images/guides/policy-management/vault_policy_binding.svg new file mode 100644 index 000000000..6e858e686 --- /dev/null +++ b/content/docs/v2025.11.21/images/guides/policy-management/vault_policy_binding.svg @@ -0,0 +1,368 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/guides/provider/aks/aks.png b/content/docs/v2025.11.21/images/guides/provider/aks/aks.png new file mode 100644 index 0000000000000000000000000000000000000000..52ba2b6ca429714cc44c60f3e19a2bb722ba571c GIT binary patch literal 85332 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 JU)=cR{{Z*E{D}Yn literal 0 HcmV?d00001 diff --git a/content/docs/v2025.11.21/images/guides/provider/aks/key-vault.png b/content/docs/v2025.11.21/images/guides/provider/aks/key-vault.png new file mode 100644 index 0000000000000000000000000000000000000000..3868fcb24ebf9e8c40f8a157c2596701376901bc GIT binary patch literal 29775 zcmbTeby$>J*gZUeqDUG@gMpxeq;!da(n?D=f(+fQNQp>yDkYK<14x5(3If8=DbfuB zGrxO|=Y6lY{`tPSuH%^*=9#^p9rwNNwbq`XrwWfr&(WSkAP}U|PaY~E5T{7tdC^%y z_}ADpRuzFDKs=RGc?2)9|NMvj=YLpug~dJ4Xfz6iiin6nB9YS4(#*`vXaoXRkw~<(Gzy+bOQYdm=qeVCLZc#35y%LnG*X&b zni+*fMW7>)D5P|RG&7Pp0vmxuBc)N&%n{5;EK(W`pJ0~8N;Cg+JsSN#T9Zbh{%eEC zh=~7e6UOInv(Oh@%h3M+9y}}-g+@o9P;j9%5(%G(K%|8a$M1PY6cKuaTG4k8fD$p3!3xHS@iMIq4<(kPfYX#^7P^S`eKX~ch@ALt|k z9f3e05%6&=0)<9Ipb*FiShgrEA_5IvKtMzPJbG{ApF$w6Afz8ks<@1s@wrVchGA=QZo;F*d8UU!ad1wBVyS|Mzitv83Ht zi7oK&FR0HhkqX#_ZK{m_Hroy<0XBh0d<0yF{&6UR?S2!<0&W_x}Bg+Zk!E{{65@TOLbAHNW+QT;mrb?coB3 z>FMc39R&piGB&RRJZnzQj~_q&DEj*qcHiSknz#xA6QZ&V=JK0vj*&n5g6cSQY@L&! zND{^JlZqR+Q7rVP_P(Rxr51DBag8l8>t)m|eIaRV%p5?*&>znJ_lu~;DZdZYwQ=?Y_s8tV z?0dzIF-Pmd%YVn<(p|wSOWA9eS`9+5^;gF)^ofe@d;! z6Ew>#xIO3AMOyZ9ILm#1jhThz zH#^lo`>B%lHR0*Zc)3abu)Id&`!$J1bH|$EpTdrBnLL&<%*f{`?`lI!*7y`yN}wVN z_uo~feI;QMr}w!b8zY#}n_7qP5m~Rk7}@^N(vls5@a&gXMx&l2Aza(R&5aioMH^lb zoZ+aD_a~vbzrQw)_u|K=^RTqYeF;fF+X=O|w~u)pts0w{Z1#w(_m!9_A}-(2{HEhP zA^rS0&3YYHd>~7{X?QsHXuU3#l1;6z#@!ir*D^BaB#t+HYpNq6F2r!^y|1gQtI6*% zh7TVfO=7c(io*6M+(U)z7dG0ihwAeuZfM$Lxt~cbm9K(jE3gq?QVL zqOnwB-?&Jc0^7CCQN#Jir)Pxva*6!i@Ues6xrHS4)Li;LvzVR)6GY2YgYT-j?-_D_ zgi*^on!QpQUel;fXO1f8b$-Nk9-jW2931?@&TE#47G*`T`LIIU*%m^5%aP*d6qMVp z1p(Ke-DNXse}n4H7CJ)xchuaCDQ259&4l_eOAL#7opbGxr1jK%7C&gV-_Z;8Bi`Lo z&JxTBrQuzebFy-Nk}71Mg-2axG04-=(Lq02pq8&Gb^rcrvGv7NZ!3hSK_%li2YQ7lfY*EG>2F=kz%*O6_G`-^E4-&sWL9`_V~suZKX1PCi@=vF z7({$pob=NrmHJ|d6?sUwSKnIZ7QH;Xx+4)$@#qW#rgelXQo5}YZew3e{s)0 zPs^=z5U+iG+dDgrmijYS#wsJ@;;12Vlhi{5;51L{PLxQsUg&Xra#V*sk|?NJ6Aman z!{iZ0O2^Ly8%o#v#L?Z&!Qn1$b=pI$FKvV zqN1i|W*WyL(G0u`JCy=>2Az0I@%EqPrt;l{m^LrSHI%>X>$CBy9I@`X5sLH|yc&0=E_f_NZe^sG5ELy41#etX{FprXehPaY#bs^=;46S6tN!b-UZbuS?6x zG4t?5w6#6)@bpyN?XSo{#)PNze0UH*-*0Dc&meAQYRcojXNgGh`eQD~66yIIwk3j9 zAxVF%!gju+x3iPr3N!PYi5mCqZh^^-*-(jo*uH87+S2J#A-}$-w=UK9PB%rx#Kf>= z8@0agN)n2MN!gxoU*~rGtwKmbUH_QLTh6Br`+R@%hffg1E~h8Xc6Qfp-VE&Ok}EDQ zrjOyX{Mk2c4~YU%V%lv8`*0o=9vPX=tMkv=niJKI;U=|Xm;PqPFyFG#N-v(K8(0NLir{^UTeI%j~Lwu1O~j@!3|mr1=;$02dTS{s<2 zWU`*Y!^g*W*&S5JLti|&$g1!&_VDl!?`gII1B_wkNpNs*$s*)Jb_DTdcK!DL%#5t8 z(N;%669}ecj`0H4DV`&ro}~*q{Gxy+Z;;a7ol3N>ot_S06kZfh`8=C?hP_lXKO;LE z?Mv%Dx3I9Vai~JEShGKoYa_wrbzqRZ^cOy;Tl7tpXK>XgZYs3ge1{^9deL60TDn#;HMd&iRuYCcM@e-dvU2a(X`(%-!S_sLVq&M3 zbq%Zxk_Y}{rt3o~@Wymgz~=sbxpRX6Nz+6oCTf(ms$+e;YS@7AwMl1;>Q_bt-0@-= z6S>$9Mf&4V7GdE82%e+aS1tQ9h(3Jy@U6AA#Bo`zx~66oTU}jkj{SK*sR=}$3 zEhSr=gf*kCuI{@(4?=@Wg!oQpR#k~K1(26ZtWJJ)d|Bx!I#@Lw)srkju+ebly|Q&r zJZ}Ij4_ZEphmd1>zMhaV2qRFEOf}Wj^m_yC?L<^mRR1w3i_^u`DPeIX0SR8+w`&aw zFy0!n_FVnLBX0Cjm-NFtgniqIvJ;HBU7b103u0xtFpT0Ei%cv$X-BSu$ho%g>fIqN zkG&By1Z16TGn0+Y%@45O>BZclAZPS{cyOlnWKU~mc9x-|0-^*FIXNo_$9o7%ec6gk z{FXoKq1SAx0UH}O_58#Q2b;4*XU|SS0?qCB0?-f*D2g9B`YqXcqW$=An>(=^2L(ir zR!YX4&`1cs5vJV<;ZafFK0XSLyK8;{kU$AvN&C0J^VeOVPtR*Tgy1cEYJn-s39lpM z-rBeu2FC}R#|N{aT`6LTrKNYj zI{-ucB1*u{_U<&e#6h=AR4e)-Jr-yM6aXjm4;hgSLxWk?bo%U}UTd#^ z57&CS6L1Mbc(fYn&y)@6>w8L2)XT!^yn*cv^1xGg(#a|#Hs6(R(Sy)HMzubQOydKu1f=?*Wy@m>hUUP0l-!a z9dZf^{2m@2B=s6aHU^n!>pwe7{)L5wHI__FOhyMA(^9&+DPp}4jzVJYXpL?seNHu? zZW+qgTAggj@eZLA;K$8uz-p33)$?uq=U1Ata@F4!!?wx%=eAN-nNq zH9?W%`AP8Gx43=(>eZ_sdC#}s9m>ec3c+hDE2|&5>V+L>X&ISockYBh&Yqp0cl^FT z4cR}g+tgyX0LgS_D)hp|i{@h$+<16+fVWSTRBkam+uGU+3=Rf3(b&`knCMn)t3{dJ zT-$j7R4;xOeP~)fpN&dQN|MvppK>i@x_AFR{;gZLRC3iqAXCMl{r}cKDibEIVhv5r zv5gUVCHpRI+P1nTR58XE=V-j7m)F}70X(7*Lt!BpC- zaxIF==38cUAKo3DTK*ouRlKi~v!X34JdL-yBcGDp*mxfU&@Un>sS8TV9KAYmMX}u| zTB*MvgF~?|?Y$n`$AO_#zR>XU)7P!N2k{A;Tcz7&vr&3lo{@_=ZHBnD?}NP8T3Gw% zoVB$z-@CuJtDTZ2SrYc@m_m$H)||}Bbn>k)VGeIvUa8Fdn*1S|fEn+3j1F{xRYFhC zY31ju#6&s(^u>xHH~*~wpRZAPj$2SL{`5%=^>kQx`_SWEd!b2YXDO|TW#CDY8lU^L zalgLvq9;O7$ab}CxIaVs;%Sn<9iQ7eLyGuFTl=l$XXTtm#O)sapyoCSjioKrjqZ$! zyf-PkDc{Tgqah+~RGMU<`o+;7U*minNN?MUCeQ|!&JEjKlDie=c&b+&}R z{aKfejzL-15ZYUP%3i;D^Q@wx;#a3t zncft!Rms3w&!dzw4hUloYhyIzcuj86}y1DFCsLs_p}@#*hZVle-^yFR8h z9NIYUEsXY|EBSZ!I%`)yeY$DdlhnR7-x>7w?KMHcI6A9}SN^1Q`1;g@P_{$1jp5Ld zN#sX%MBAS14)c0rJaB{N*mniu>j(@GfV7OXG@oPtJEv)%~<3Uz5#AhwK_>l zyYeUpJ=DFg*n>0+w56^u_b%8}go)K%qBH zdG;^;6<+tcy)S+B-2B|!)aq(TWF#`L4JyQ;LcLx{{I|<$4XEc97ojK;)K70VY#14# zDXE-s34y1U{Ie@7d7S@-)Ju0O`d6WviDpyhG5mJ+vwC3x;lC|-pE^x?d%FG=!6`z* z3l}bYZ23!!g?p3y7q;#HGapC#=H@lZ(Q<1hphi?5{1aM_eV2Am{cZGoPT2p=>iz#@ z=$=RtgnRouW^|1LY>fzuk8Td;top|OUC>-~2Z`r3Gr) zZkKj`k3=%5=g+jN=E9g}Hx;vW%T8u&3=C->6LcG!M9uuRYBa`|{UCWSExzlWl3VG% z!CHD*@ADyFa`7i>YL@|L8XFr=&CWi6s=nfAt;*J3#JLalz89{nTqL1gnXF4KD&jgm zJ}&r#a^Pu53V1ny4H5JjSFSH~KUZ;5b810cla6&@1f37N*pHZMW^V34<^jOi@^L3R z;GTLZ-ARIQ3lLV^mH-*O_Hbilv!dTcemkbZ&>Xz_65dFm4ao;z>s&HqOyuLZUIDO! z*m1PCI-6fUF#|JH4c(&3uk95-VlS-2{4pV?t>)s)R65jrSW&XNk557X12;d(bc1KR zHo;6MJ0s%_EUoYPS^@z(BPC`Rsi{9*l*L7SNrLl-Rj0{j42{eOKU2bzYOac8)%&vR z$R}dpM0jy(ZRQQ0pisPx6aMhF2kWFU&-c9Nyf`p#Rkh0Rv_2speEAL+i7#+*MK6ar zECxR}0}ZvYv2n8;6TjsNsb_9(u1LQDpZ2b08&JE5jpf3+tpP=e>9w^UxD}av%`y%* z5zmULW78;&Vva<~k}%wpp8E_?`R%NXM1nr?+Zcz3EAh<* zk>TD?rqWb%)exr+j<)+{IZv*mKLGK07daXQ0G(i?gRO95yH^5NSNHe#yX<^_%%;6A zcX>nVm5akYfdJyuZYp&TU3G%?egD0`{?o=Kty z>dX~$NOrSXiB^q+gM%riUo?Qex&)dXjv97$c7{86WM{{N0Isq2LEm%}xj2rqxc>P4 z#*{Dl1x7{%n0D90`PdN@GEqSV?jW44k8*I}3KX$WpYibW5|NRyunNR_c^+BR-#K6T z0;>I+?Ci{t;O}Umie7xb)@91OiZ0LAtMh_FR~hPlcTCAV9hW{L)f( zdc5w9y?*T)zK@QGbFsy)1tBTD%d`DiiE={q+j`G}qT^+Gi!_m`*0l|>($4-VjtpjI zX29)sBnjEOEM>;tymiaq`^QIesp83s5+^@W)~lL>iAeJsfP=-m2TB4Y_}Na*y1C6( zrp2;h-Pyhm5AMF`^I=jem}{Z4{?^$U3|yz}qK@F@h~rs9fVl=*M!mCXToA)q@<(> zfoTX6yTi#DT2xdNT+75sN+e{K($Dh?E0rXs-&at{T7proRKJ0vn9?MDVPK4aIWDyv ziRgRUs{f#Cx(S{)UR_OiSzrKwKu}2NdzG`bTAl`I2c!pHhjxtaE8GY&Ch;yP;Ny3J zq`yQ(r5B+th}+Y1))(%=o`mJi4S5y9<;v3FXVrA)^@%*4^7mS2fcCBw5)$f)Z5$nM@bFv!2nManRXMFb zdGh26H+MKhCKZhyAYgI;Mn*4xh2;htsTr6WsO~;McZILdStA#Fl5w1bLbAyAQHmJU zSv?_wnPk1OaO@ zAK+_3MYqnvCMYj-zHM_Gm-N(Q*bL=-0cqigumGQiTfnbfnp;d&uVnK+4u_lh4p0h5 z$AXl$q7#Uhr^e>$>N-EfcIVCwR@O63Tpf2xG}xn}qoX_BWk7lWvOGI24H4XI*YXuP zQheH5LIUU`IRN6Y<1*ntkk|YHUfJLfpT~g>Fdhd`j-Im?Rv5eiTrt$pv07d$Kfmx= zc>_%?C?qmaVQYjVksKUKdk8D9U5eIdZ)0oHB$Qz4GTZ-tUq*(c_UKORyQJdn+q`^y z(SDO&oxHuGO_7S?(mr((!*{K5#0iL6t(N>o{E0$#b5AN0hwbO>ot?`k1>Id-`k>0Y z%&wu|n-~}OL|VGt#JbhnJE|=qALTY!FyB#Z)?`~ab1wpDWFyS+A>>(z{UvstRSrvy zK#B=^9Sb5(pFYiwSrc(fN&0YIR5S^oWtKv6$DQ&qL%l)}L)o<}C=ewha?hTfhbmt9 z09P3m+*5z3=xeX@G#xK95?xl{T$`-V}6yw6K&oB~65Q z=wGS&HLsP)n?AA~%7-)12&r}TCLsjjQ=1h=?=iP+9Fx~cc!jI2>+RZHXXok5OD9pLIw(#2PYpsr~0$I-U}&xd!?jzbU-SUu^UJ} z8bO;YpgTfp-hkZq48A29@z0i^j(qlgb|=^va2rT$)k>1S04@@$*1qPB6~BIsj}yii zoX4Kcud=eT@*1^}9G{%f@ED)HdKKmDGhCn}3*ZSCj-keJp7e}`7@!Pw1O%6}WGGUu zJ-|KOz@$OcbOnus1_l(8*(FNKk<=s*C&`OKl8bP4A`p%Qg4+wdtT(yB*2b%1 zi8X*$T6%g24wt`P0IP~=LMWPCf!1~fk#f~YNbr=noqary$+=#!{UkB!jn=P8g0`;# z?Vu+q#pfYZv@|zoj_tfa==CPc1}}7*kCxujcQIjgO-;OlCyJ(I~oV87! zUZNIEwUsJR>*?v4CzQ@30cs1VcE>4P(QxyHjS~$`{I}+2SPTtRdLEK63=k}?^0EcP zjq3EZ%>o`Dv+KMA*ySP}U2te9Ijr5%qoyCa`C4U-lar~~lXdS>Bs#`Qr)qT4K-|#? z)7n5vPA^ywnvb@X*5mi|(?b%X`JoUG>V5FYTp^M}+}a~H0eN^t*qt6T;Bwl#pp!{L zL_}n}o`4*|Wzume;QUy_o@Qf5G+QM=ZH9hwM$umzwO{_J8Ux!X&)>!6Y)C_6{0=vv zI0x-5EG{lEJ3ITt@%3jO5?_#$o>e&^>xUc#L92n{-)`k6H_Q{j{(57cXDTXh+Kp#` zEv=}k8u()LnEf*G@=$&{T!ol#A%UVOBQtZv9Rbo*L`us0@^S&FbP%Ai%q}eW$Hp27 z{9Z|-2ljX+b@@krCy>Oj%tJkmH-VOT`}Xa|-X6E!a36a!Q{d@M%!mmm($z48KZON+pyM^j%U9zjvfX9`9}FUk1@;MCe#Q=t^{ z1y0f5fD7`LsF+xedLbiFz;X$9i6kT>l9H2Y0ML4Q;m{>7>?4Tuku z9YD9rDCWimv+iUWuUalDFIv68gu3Y!R>fV%q809NA6WdKGt_99{z+-+^SF9$b&V6Bgb zRSrl3fJ@F6{R)IWVH|_o*>87hrp!4p-w6!2=4Pq;1LSiWq{6MuGNUt+c!RbF2HpdMj4%cR1h z57N+gC?!ABb0N@oO}>BsKHow7Nngc@l{K6A9JLQJtrcnr;V6)e+Zuko02@GI$-j=E z+dHu}DK^-XeXJ2(4ZyotM|a8)QXK#9e{9bFFRu|UVW)KQ@3IYi^63Be7=4{Hq6NK0 zEB{}oj~(UL3}ueDZK}tu)2-}B*!>|n{IutWKTl^2BIFP&WU`GTDt@IIwE92$o!;D- zwcz<2cKMutzVaZdXx1ezk19@$fy4~qm19fKlzltnM!@SqwTTwmR-#Y$HLK=+U(!I% z=jYnK*3T}M$sP}*zaKMr`MNHH+v}%`#InmyqHm&jv_?DnE?Ef2stM;0Z(1-%S0Xk% zU)**~lD(ZgwCKV&qnLFk$LqD*0(`-)#Ium=nW)l7gUT=TIcm~MU$MRp;&42zFS)Bi zn+O;1A3UTul0}y6caciZ)5dmWlgbjADhB0O7v5Jgf9_X0eM@qM{Y&)zqbIcaI&V2| zB8@dE(Cnzv_`&{)p0X`-qkjAmL)$a@ZZ^UURVw`|{-LY3#%LrBhFv6nPfDNVBsXkN&YvlmxCY_E#}$mncsg2vE_JE35npRm z7VkO9UY^HjaC~hS+XkWj{d@cm#I`wauFkVF)%KKkr|oLrBXf3HfEITx^=i9HqW7b` z`L9=Ru_f=Rp*T}h<=h)30>10IMk^dyqsV!;EFE2cNW^~8t)z%}}T^3b@SJOqACVElP0zIs;0iO0SP;Ry4ktLSqM%DJNV})Dh zyxTRdBArw|;S;W+OR>sJrOyv_tK;X-)F;Cm%6_GV=c--#2Gl0F3bk8~7ImMFj^T5% zn2w^jzww4r5!k^@)zwE*@tojM&&Bt4;*CTrXsP^ax2Hjsdb`eTyXnsl#9VUQaF9YE zJjKqruyHNF?vJ5z+wf)`aC5)3F?l;9pM7iUyMvad;y(Ta@n?_G-`AWOWynvZCAwc_ zI%T3Jj6{ahVWr9O(}La4EBo?r+(f1~C%gAsqAMoy!^|7vqZQDWwnml-`PF+?kAU`T zi}xjz;`HWwgWEoB5^*j6-JnM)ysP=wkauj4Gwe~`9tf7j;izj^7r6R~pC+?k&Usu# z_7F4uKQ-LY^IsUZ3oX)Mc zWCY+}Q{wxVmONIb_QyYSP3gu$9J_oA$2Cf>C2L>k?PPyW{i_d?Zs&yrcKfY+~ z?w$`3xnCIgN9xfoj!gi({G0gF`O2tQzMW&sQ=!8IP`kRgx%F@USw2+9Vk&@pp2P7Y zn>#zDg;fqCJP3ah#&-tP9#ClElqGO0`9l4VpI4DQcb}0^auaZLyYMwU*%x}e*-XhwF0#&6cbht+~&%L)&{^5E{h+Z z&UGFDb2L)r%n3F=S^zmd`NIwIptDATp2Ka>c&f{E{9MpYSXkbQ)n_HjnUu`z96@)f~H)6mecr{5BEk@aVh z?e&?i{EkU(S#q z0L1oI=`pFYl%S<;h31{FVF4ny$KJquUY3SM_N}t^iviQeus_GIAJ+5k20PTRz7GV05ANT*U5wa(MTm0^;RvvCVaEfo zQs7Df1Q;E0E<1xnfL3LpnP9TDtHu0ziBEuUV{3a=Oe`5@+OSO1e6qI2GZ{R9EQ%>| zA$?Dwa%coOTgYW&ipILjd3E#==vIJFJ&re9!HY)h14ftU4wCSLUXQVE-ROrR zhf}VL3%0zS+@k(5LC$*dUA*19%({^lwW26$hh&Ne((w)X499UL;=w`0makyUS#h=F zP@Yb%z0$)ur88uhnRrS7U=ZW4u&}hGEKE-~0IkpiG2%8oaSn(@fW}CM~Vyxzz=d2^Xu7!H`Wto z>ppDC_U?8AaC$6O<0kr3_NzdZ7uG**uWUp_oxr?J|Ni~9+0X#0ls&o~@OUUe1$Z=o zQ|xe*JI(bNX3I1h2*AATE0 z@&QGNE}z6H$hc0dPt>d`o>kbDI@rD#IyYyGb4G(O=m!D1J5hl3#tpyXVx9mG;Ge5s z?5=}VvIZkAE{;=?cc2j0t|d4_Ciug7$X~9jhef=qF6%+9Ug#wyOYS%~XKL{^g&m8v z?&`7;dg)tPlAqXk*F}=C`XBw|&k(y5Ia45-FZ*Ic@`K8&f^@rUa;nx4Uv4!=MKxqi zZjWFkAB^e9J=9t54v#W?D~mkuN3+ahuF;uHR6dG->-?a0keg5srV^-XdQqEuteJsr z^XC|o&e0#At|0>v^NR*MnK@9nK&jnf*DZbnG^d@$!t87l@Ey-9Y_48pd6x~o<(>6O zCf00T2|7|TvMeCPJz$%Qp6m?F$AE>jWxD(XLL{hi1U@hbP_+5OsDSgU`p@s&YCiJ| zQ0V>0Q4YvXaXZ(<)#E0A{UbQ?kMC%Ieno)?RO&-;UBrpGqne&zAO@@eZ2>u^KP4tP zSsscW7&zn6QgdMVd_f?-cKy1L(+V}tQur%^`dJ|(xE4P-=s;RA!g@m}2Q%=kSk|jo zUjZG3+eh{M_w;~rt@MDP1bt`~_qllQ#fzKpiqdM`@JF51xXlr^sj;!GqXX1oId3e8-IS?1nu{ZvEwhgBOm3CBvrSdd8V~U1?U1 z0s*_#dUZRjN}@cax$xH-^1;h4V{2!8|O%^p-AoTk$cqCUF2B#}yC3@_s(DWS$9@P{<8AMOM%ivH`iu1o^qk z(W(b0aXlNZtF<2D+6g@!MCX5;<>Gz$;PSS2kI=GPOFQEJvoA(9yxWSy=+5z=X|ZEh zlTWiGM5c=aM~+z|j5y49QBct1fD1x6$O6S<|b@f z5)X=A3TRm2VA_JZ9!HBnh+!?XCc*Jk;3363OGE^WO@o&a2E?DFGI1b8jpsX}_vm(& z1&-wt`HTP|>@gj|c=GUe)(OzSW`OMjdcmclkcs0(ZX(Pt!yn$DkL+O!wJZBEpBq!b zbsGi(%+aD3(j%^1Jkf{-<$33p@7TwZP^0s)YH}~q;%V_rWjggIvQ}g~dl{~Y2~wzk z+tWZNjha`Qu>W)r{@Iu7ClJiP7^eEve`LhT(~WCn#s+VAgM>g4*70|RaRG&t#6??V9p*R1i?*(gV(<5%p{;22Q68SJvc*uIG_V2m zEwoP*6~QWkfXMk+OPV)Va;nh%@uyV%_8oC2FOo~V z)K9bywdkA#vFLT%i0{hPnl}`Byo?2^?prF_7GX)M zGRaq{7%}YeMfa#uYUg*{Gh#0I&W>chIbAVjSG>OVKi2MBvk7=HzKLC*oJMyT5nCK^sU}| z@kcV4A>vU514+E9a%{)iYMo)uRLz|1*U&S2#jZ`XUAH!F5KXCa&BRAvbJ8A0jLcJQ;5!;yG=z6-hwOjlUUekuo=5NmZCJ#|IZOCP-9AU99#P+Z%F$N`Shj;heY^tGi}2#7YiZ!R zSC8pEk=FJ8?q<}nO8pg}ot;?~7eWLk`iO2_v#TT^%+AuUJ_jVOGI$k&`7zx&FW(cB zQYS6Jimh3wYx_X^EGjpe+ zD&EG~c4pj`&z#4tFM!~F+}Tn^vH|71P-d~<8q@|`ZmB5)gQD{8r_ijs z<+FM)>UhMKVr_M8MH?oDQ~t<4wAi4Fik>qtwybX(eG^_5iC_5g=FYFv_edwL=sR_F zGLgm^+1$=UcXizsue;YH(w>zpi1JVKiM#I0vp;$y=Q?}i?K$Gr&RIipUbBVAd&I}5 z^}6Q{AFoZPw-+kg*nQiXZ4c`DGv~RtKGNLTE8693UuWFiF;9lZE(9-qqZh76>G6O0 zb2M&qOG_=J=UN-Q|jY{5^T2Gt$m*MY|&uL+k_sD)wFt@4$Y6i-1~_cu{d#{Bsw;d~P8Wt@rI zODYP?tax0|tDhSKGH#PRaiu>lj(IQMLnuW=9vsi^$NlMf`6IZr`;5q8^x}$%v5D!% zTJFV9jGB=Qb(pSECM4cz&^tCTI=AlJnqTl9@8~~me=wCFOGI*ZVSJb+%-im1Nha~a z#zZ1#c(@gM(a&Cd)@6&EA=>WIPpt<7_#j*yulk&A!WlL*v#HT65#_YKbP zr)_p%lO6|2E1P}K(c(;TcjO^@97^FnM}eTp$*Dfr3n0PnpX|_ih`3e?(I0pUAUZF5 z$(JYonOU8kEgJXJ>t?=Ie3e{OD5YoI+ORQW|GD5IugCH6i_vPzx+Hoo+gU}nB`~A2=A=LS47fKAVBjxtQH0m=zo1yLXUK6ycUo_e5IASfVPA)8 zCErFi^-6?A&9+l=bar;%xO2lVtdDkw&OxLOIr7j-fh=*T;G?du)Q`^>dtQlEwe@r{ ze>UQED?_%)uhNFcr%26w7ew6uJPdj*e_(oKk#lEj9PAFXh~d)6ov1<%*JjsUB`OBWQBt#={@h zpVE~I&L&4ZD17Utpc~V}89=<_2eYGcLw|#+?!66U;)vvA&qsG3gKrcP`=VSGbuAX- zE)M55KI<&YrF3!D9ek1(19H8 z>`at&epeh@J`;PgqR`dU-0ZjJiD`}@eW_7n$gShPJN<{wy~qg7Y5B+eMzZ@@UWs-tdbkM)}G|YNsh+LVM=V{nFv`#vJobL@h2X#8gR70P(T3v=p1cA@K( zvGBs4I3LwQM%x4*TC#mIn5Kh%{`}dAVNgYRsVBghlNb)M6HPZTPr#YG1Fe(}%4D`Z zd&>rVM(^WIHi;LAKIXZ};{-vB!<7#ktVta*^xTwQ_bzWj{&I1_QxjggO`$|d|$|t>!D38Rnmv(dWfE?O_gJxKx zo@nJP&n+UHiSg0M`|SscbsIC8W9O}hM=wP&+ut>#8LSa``g`<(*)m>|&X(YL;nPiX z@^UR6WLaL1Vgo~MKhMMwA{f3pu(I*`24VNFY}Xz~w=lCIy7j%Z|b?jxc9XG$$xkOZn3@}sBxB1V8(j8 zJ2O(L4ocV@Hwkm4`CLo%VKcmNv*P93%6VT|&72nr5jiKnx!sH1iW!^p?Yiacb5Ge5 zunlzG=q|g7DJgdSvg)?dynB{&-%e+0F#j=`)pgYUem)1FZ$9X^J6Lv75UXJ zx7_`twJTEC*O+vN#$oSi5%Q5dp|}SRJ#OXGJ=Zt4l2ehPaqqc2Gi&uBig$aN zMA-EcHy^j*K)5KQvwFDdr}<7_*Ke6I;c98k?L#U#i)!oMiLa_^gzU>r^eqe@&Jr$s z%Ze_Usv<#Q5<)XO;#f$#@G4@m4ZiO`f5X^yW5Gg5M{E!g6}5b@6JS{@7}iu6EAwLQ zQ=^p5VDRswKzyF9vI?~Nu8K@op8i0uYpJzqd-Te=A;ym8#;!Ny<)%}!R+2ih7kijv zz8I^s(0TQwS5#kEpOjdywSUAu5#HSJ>so?Pyph?B0rIm~-y9qzf?NvRlW}{*4REf1 zP|A5Rlt%;JK|`<$ZNXu-r;a@*7LLbs`}d*Ze*%+5oM+b7-lwNuho5`M02<)u=tP{-pK<3&lez8Q?TT3SGLv>` zX;5)zrl&vT9UX7?KFb}{(9$Y#TGfP7wi#!xhNI(f{xPkhBJOZ|aRAPenj`{)^AUR4 zmxc%8I?fpef;Y}S2(}#%**}z)suZRq0ue~`*YyDPn<3Z+z-fAkj*bo-EVv`XKnz}I zV+#iE!)ChibYo*9@VUN9E#cQ6AMDOaYYtMJ1^Sr;oEKoSI^K6@?xfx4WEV|>;|oRB zlj3>#`L@o^>c0iyGta(%fAi)I?sT7nFaw-y%mY~*mhSZ8VgSf5O4jD)x4>2V0YvM# zcvT&N=H})vKqUkHf^!hyR1i7=D`q}EN+??2g@lZJF**Z9i_AFCOyIH&f)jR;2?-rg zE4j=^t7}v_-GQG+V1)x<;3|PL-Fc`~YA#F+x4 zy@3n|IiSROUDw0Iiuni*Y_kBP+4$o}6jWYJAapGBBnQXG(*XU+0v6WO#FvZUXyy+K zK6s*f_A0|6?U+#mpQ4I41-=W1;H!LwnR%YT$ zWm~?~8WiOmREv6TZ+as1nYMv5r}Kd0E7L7k_g^DB#Bw33`>M6!;pYqGTtj`$E^07f z#I(qgjQ79XbUQ=Rk1c9xSrMaYidtg&b;sMHo?-%OqkFSIZvZAMNQ?mZUBQua6*e}3$8JH|EDzxX73fP}&E`hG)V15>dH zwy}$+H&u%76p@T zF3rnn>+n@c!?sThom-ABSxF?3xxG`RHu_1vDA(wnUnMu`a-xB`?l#8z>zzn}A>HQu zTA`Q)sfT*EjQY+Hx$vueA3!IltLaYPa~S-Qdt!PcjfdAz#aT-(B-iaqwA!y=iuyB{)`;2E33)0%BcbX_k3BBAiAqY#zHCWnXpTM#tU*@>|?%lhe zPM>|Ii7%M1#@n$Ivb&tu5OLBV}fIPZ{5f7%p@l(L6PQ_n+V4=MS2h49T z133`~@)I0h-`b=sXU(_Rm&4GmPhlY^{8GYn;vFpnPEo}jBi}F3 z!378(@C6pZZ?WJk)(~c>MO}(?$1h*LjANEp1xQ(OQBb`=8}IWLP7u97O$`L`+0Izb zGoS4q0DZR8Ql_SK0Zz_7D(f9elO%vW#Lv$UcdO=pkB*l1ZBP)=b*Xn(#Klt}yCd|0 z?*I`J{%p6@f5T~QOd5I;`1U;uJG)%rJJ^O#l{7!EtkYRnQmcb}H0r-{awzHW+AUzjpQpV3>y8k!pFh%mMMxFoR8vQH((&7bul*FE3MG+O4- zgK{Z5DGF~{vHqk!*I}!8NwMFXh4Gv0G{h_|MN5m?uiZxQHhKp3I*#a(UDU^tjbhQO z=%26G^7Gm{hIu}ism4bO-y9x0%kfDrBuX?d{bZH8zt&*HKhXWMX* zsW+L9=#Pwym~HLWuXmk!viE1z5O3()8fsn%F@@R^rWJ=yN*)s>O|6~F z+j(-kcRb&LPYmAIj}R$8^wDxuo!3(FS|I~FhAKYJC^gZo{FKRY?U zPpaUzJ#a>DSle)hofXmm*trO};72_!b7;4PU45{VQtPzT|47;j%9CsgpsabE* zG#t~O&B@-`_Vau5=2wkwi76>CBI+qNlV4YIvQuW@mqF%1cRn~c056vU{H6mWBr=?z zNeKfE;r8rQFBxs^F`fN>2Qb^h0Wx;Y(kF*WPj}}|gn4;+=RbUuN;mjfWZ>|t?-is5 zw$#>vfykwSY=S;;B?Gb63I`$Ku=o{G(Iof+X5p z_x=6#`|Ii9IOlxt?|py9^|`L=ODQ=U7!q$fCtZEcNtQw%JDPL7pHc>S{dCm=xT z{IK>5Lor~=7N8Aul;^G6D((z41VeaNii0R*d4QGy;wQVuW|!@{@tZNu5ILE-*=IJ844;k;(rj$&Q9h*nExbwxCBu8GrTG2 zF%!HA%DE)I0@Rci&u@e1eR4k2*h!gK17Q^7SCR1A&8@LF^~AF09}%Id9jVE|`?8p< z$3sM)9A781YxgGBxgZf5hNR#J6*B(m-5jEgA%Y^_KVsK1BnGW!DtTJkC;ygvYe|}- z_hk*o*iA_r)%I>VQ*}R6{|`&Ouxru&hmR$t277fve?7bueI?Y*)5e*OqdR6pw6R)B ze}E9CE71a+%wPLDE_YtrS8j6LC$sdLx*!tW3$C0Pg!ON*$=DGuVJJcL zR_EFrzr@T#h%gLc5T+}jqi@)>sfvUn!_2G#KbsvpFk$ZWPVCK5W)MGHo>5v}+_MC0 zuiAI-o8A0dEP3d z7s5n@$oAB!Q`)+^i4-0nlO8Y|`0?vk>6oMw)A=Juj}q-V)f=LKWL4Hm=3=LJk6WLc zDPKlk?JZ81<|PL05m>7+6;3S&SO1(z_~-K8-hucDv*WX^^7r$Ehx>EHw^$$D6fwe9 zCK&D1=a!-@B~y2Lvuo@|hAYL-HY8JJe<#0Ca;K=qdmnH-lD$uZF-uCe_};jlgIQz1 z?!9f4`J>q>V+S@awN)r2z3hHI9&mo4zpSxafajDETiA&wt%|K%PwFnu9J~_!_uVe# zK3De(XmU*JdDF<|a3l2nTJFdp*+@!`^y}Kyn&Q7+y&12*sOr7_I?G`E;84|P83DeE zxS03{W3F=V+uFd(M=p%`Tyw`|;1w-y657Q3eS7GxKs5CkRrBq@>~q~+ITq~Fwk*5L zXSbugbRE@`arpq^4I4=3_LQu*U0tV&Kb?4{2QG9{+emn`YvBpm4_#g49Q%(EEfl7j zM7QNnuh00pAUD?>b1e`MRF>(R+ru$|K4EO!h&eZ`EKXkBOq5+1l^BTl;kX(XIbVf5 z;3uf=9O_)B3N_>Gt`e$J+2hT!iXnvs1=Ua(VG29!;4*giJgV(KL$oa^wxix+eI7?2z8=FnqaUpe#y~25^iN zWWa{$75c>so0QmorBCGt=zgyiFIaFbxa)L>`cpUCi^g(`ZHt|oM~VKCtcuc+z_Ng_ zeP3DYYlX5#J)eJ1c^I#h+7wbJ@^Z$sCQPBz=ck2cM_}j5wGG0mby*27lxp(j85u_( zZd{0^J9<<%{aosZdm2 z-niIo9wtb{`hbUrr(Q2mOW_Yc#z&|W==6JgWFDp^kaL!16)F3ov8|0&MMVY9ND<#Z z(SY!+rdtjqM)g@9{7V4GI1jh*(O}7M1qDg^^d=gB%A4rUY8ZxuFoo3i6Oka-d&ZGw z?)NuL{Ecdxn)I#Dmw5b4%xyyW_5=u)3YM~%;fvIqar7jZz}a@^3bdtYovbf%TP6Z? zAROMm$8}c79FG(=Ye`69jO=-KV%Ol{;9k$kYEd^G9sRua&6_umX#5@26Rr%Q2F=YR z90LhMTwEOCGpW@!{8i2L=L@qx%+PPi#f73t>GbhUH5ki}!#L*RMVGq9#=}Xi5K3ph zcsxb~fso>5MSd)X}+j-+plJ^2fSw^+nT# zlRZuqv>1n+Os`N~!?Bugy%$>`3+<>OM_YG8P~v;F(%!V{QQ2JCq=2*BJ}Fg`RmKYflR>eIv84Sp~;a;Y7fJ}4 z;`*hw-Jh2$j$3}Q7ZlEXGUd0s)pyS7L;2>Kgm-Q~oh82pM%tP9ec)N15&x{XDEX}~ z$jVuTQ$Xd-@b`jEn@+yBRuhfuFFSl-tY_E0#qnk1eJrQ1H~Xb2EcbA}r#ZDRhmVtq z`u=z3UbzbIz^#fJhm3?APORpuQjGC~9h`tbD_HPUdN*{w7zAyAK((|Pp$77@7O2bf+>fCcrxh)bX(CstKt-98lLLD+Eun^%T-YGYjCWV2 zwkAbbh3(WB#Qd`cY5~a22{XW|7yO>p>(@Vln22cS>orC)M=9A_g^sYcG-$YmQ6LY#&sG&g@6A~6Se;3r4mk2QNDz)vEU=RIxvu?NG z#5b4_Y~5{Q2`H$3oE|dQZQy5-rNFzCJzhgBj1(2&6T=HTgu`WC)AkEKFbMpV*Q`Jk z1SGM=FE0fAnHp*Z>kf1yWdIB#AM%Op;h_G~EeVTius{!i$OW~y5HSjbYKh1%QG30A z>Sm9?cNG3g1_lN)XDu}2)U2!oP*{9LzhQ!AQFNsq9&(+NjX+B)`z47zPLtQBt`uyvV8%DxyZ zA|%`~Xm0a#<<5E;xhzZj=h^m3-0Kz(1{G}7brE*Xk*cgZcw0cAWQ9?_Q0EqR3RN=i zVDQoO%DT=MA1+8p$-F5KZG29WRjam+&LK?dLo1piX~@N4Rdt@}t>@Z%7bps8M8d+t zlpzF|E`VGx1*pt!i_2g$bar;a$d1w8-kx~32v5kq7}tbF4fL}a2C{mLs*pvtbB>zc z(oESQCdLR#{yaw_tu|CWs3s8uyi~anm|!R;0_TrZy~6n9EHL(n`O`n=Qz>QTPZy7C zXrQar++A@<1C=otTZBo_jyIX$YcC%kU7qh$VYTXb}^J|)>bx^mFV2ohGE(9fCk7Zj~NE*O!v zxw-icYOoQ37vTw4Sq6DGOS6!0UBpT8CzVgpSBEH=Pnen}^fAUiw(@g_0~*dD%Sv>gLn&lBjbFOQRq$ zp$7oU(%i!|vlUHki0S?=s5Veap*ud}?__BZCG*=!GFx$*b+9_^|q zrp#KjG$~)U{rBd#!f>%~5=0E6@9F>j(Jhs@mE=22Yq;F?|L>!AXkMcyYw`D8_8cSs zcA&Qe8WomhAhoDn6dg?$g&sj4`uO7q|+R^QpWY) zJMfq>%htw6w`|GvlvWkwF$7jjG{;zI+} z!4j|KhRl$hoVy!X@yeCPE{A7W>YJLIRWc1M?B;6Tz0*d4gN|zidUl^;vO;GGGy(1! z*hL$WGSSA<5F<8JD{tSwpS(I&+t5&nNCP8E%#LWE7ZkktxbVB|q2JOU8`LPyJu@g% z;Xpvl$aqFCyo~oks)8yWN%ojBEAu$7TY!n4-eE7VIbWyvu$TtW-oDS46VnqoX)%1D z;9na!IE2NtoA_8T%m=rBbQP#wv#ouk81kVx&O}W;N8vE_!NDJh+Sg@W{H06z$)0F5gfyb}tHs z*A5MLf`SH-Ci5?!2WC?Q;wW8*g{5T`nu5U4(8%hYOA3elFK3SGye!&Jd5`+P%i8?#Hx(VL=bm?-K6{rc0#Vi%fCn>INkqX>*_tr@A3hc)|$jOYmmgfh9{Qe>02&M@)X7N2)N~uM2%G+#=R1FiYV!He zC_7Ri?c#=NWLF>ahc3>}knpV1uC)Et@(Wc~7$`iV+C0_#e`sQeGZg4zx- z_!#uOz^*+!JbqNMY7P4mhvs|H(RHZsHIda2!NHvx`PS2#q(ZzVckK!Q#s~j|y>6r7 zy3DTty3LM!jTaITOU5Yx#Y%|8-+F$KAz@Vj~w^*7rNn01xqnug1M$>#am;x^4{yMazv`cALX%ijEq#A zTHr)2wY_oZl%ZUsJ&46YPd|Vo4rS$*tu{7m*RF*Wlvp-kFnOW4;JBz6M4lym+$cm%DzUVPz_}sy@iDZn75S>CD&l~y+V)b_yDHI0?Ek) z-2#u0kWLXh^A~dq3XUf0J~l{4KUWDdTlOP(hhds?J1>lt*rS5SSpU2k{V$1bI3cOP z)U>CyrGr zg)o?)8zEQ~6%`GaM4TgnayEcjH28{8fA?MLKYsi;3}@FZEgc}RGpx4~QOYi$!yqyb z2(I&7M|7{*G$tgL#$p<#gRBE@-Q-ol0Yhd2O41ktMWCpagf$oST)A5EAY?n0C@qkA zRZm#3SGT%)^9NaA{;_3g*cQ*KT#>tczxbDp~rhAGgC}C-kXUg->?aO zSjm5*LjJ4T+FKM8?-1C7UL~A$Y$tU7$&{XLIDzESu`vDz)_mtj%>|Bc85zux0{nKP zdMNMyY9I{LorJG#dKxvXIZS!#Sr;D?t1ie)Y4pozv1f*H=rE9bTUQrorW~+>>{zsR z>mxtG)(3eA69By|GsgnNVWbqov5Xjt0e&hn-w9U)BC;&)hxQ(m$YV*Ye!U4-Hyrh= z4Y(B&B7m6`;H<``CSn7J#a4?-g2gceJ%TuH^asIxr6p#%xEAlZq=jH|{CbSF;B6Z0X5kTV_J-~A$n(qbkyc;)OD=8_F9DfX{4g?4} z@W>_Z;6zJMaK2j!AZU7MdX9vYliHRYRsClm*nuS1t9Lm@+97Q{x7x8|;Qx=Z9*m5N z%KKI_aVs=PDWwgJi`13tc%PJy?dl#I?MP3N*Z*6C`AbPi@Bu!>@)2ndOd(#qIM){5 z9RaJ{Kyb)6HddU3VC>ZC(<5Rc(1)QLK}P-wY1hEOKtcu_C1g)&qMAlk@xr!sFx0Kj z=bNdGjS89w?T++MLwr&2MA<7R*GKuPhL{a?1iWckQ%4znOPX=ms2oQZ^8M-k!qEWX z&uReoTuu8T9Kg(L4K)=TC#TEYuXEI=OOE+4NWtPwA$-3_SBQ4{^2t2zl}ZLi)-*IM zL*y9&^z?)mi<$xVig=&T&h;sDqjKQK{I}Dn^WRDFK{&La7g7UdX-a&_cFoU(rP{-{ zFw@wybxf;}7Irj_5AU_Ud1LJBT#O5cd}rF`W`!yBkVEU0 z8yg#2?DF;W^gg;cCXG>;aI8D5{fj*JPL*k+dEr$so-hk))d>9JxX1-84LBsJ*uFR^ zQWFi*1pvL%($SmR+Xv&25miWT?tLhdH_*7aOzqcu;}8ycrO{ zfR>~F!G2)CMDPNy4!F0zl&Ro4pmym}=w!)mc%q1ikm(oJ2mt`5&ALKuA3v5>vrfj1 zl7UB6Wf+<=IB`$Tp)LaUC-V6REr{qa4yOT%&o3p#O2fdwAZ}cwy?KwI$md^96&2V{)P}#mjmAd>aNYhy)_NZh(ry z8&hRDafneKQt@>gV`Q667bERtFhcigzy_>=*EbPLe1sfA?i$===&$6b8l}9n zI7G$7oQ&ehx#oEk6tq@h$z#par#n;igmGcW5Kl~Gy{`})Ra^TNe0x1$J1&5ukI*E@ zyatXn#unTlx^9=0oGhQ@`zQ>nYvhV4%-gZ$kkt7E1&6Z=XQrlhfQ1gWIWz7Wx>Q?; zDnrURaYs+(n6Cn|MMM@}V{;5Ee*kxp!s!_wA4g3&m>gx2cEPI_xwVX^LFpsKx9mIL z@8ZSrC}|VMJH=x&6(2vaajvs48R=*G`qG`UXoDFPQk`zyS?6AqMz;Os2Y~S)68!|y z=z$A)>qGw))W2p5W7z&XIu3c*mbsn&!7Uwlb=3zBBwkwjH&Uk+nY>+Er*jr7$C}WQ;ZIDr9?Ud2j)!uP^7nyC$Wdkd z`}gnPUcFOU6&0{D1JKfU(w7uP9(&Q0!7zil@4SP}ScWBMzs$Q7rV;@Tte zvN>x5LILd8#ss9{iC_j#$(i=v)9D@eVQ~^1d^}(A8W2xN$gnxPmlkKP;~@m0-20!b z3idNbgO2h)@gE|<1vQT?)_3HN9=^Dl*<(rd0SH&DQLYoq0ngQwdtgs`8zp@kCNbyM z4_=jT|FouQTuhr?`84&+Qo^3E{j?4emycC)wA;Dm-%dm->3C{Ud=k~B7p*^0$yHol z^ycApFgL#z6JwN5-KF&iP81BFl3-+U`h_#!?y_I^Uzq&VmXYkJJ@hx>^+#rBPn;dR zS&X%UVob-tfc_xb@wz-(-(y_tiTw;6HB!ubsJ zQr+GAIwEZ>Edd^66pBJNhRTJ7n>*z80!dVk*()jI^4o5^?&0d--soX#l?{0`8W$;ukO9z-^p)*L*+->|IE|PAU-9quJ%G5tDV^t- zna-!|)HhOqPP+Wh5GOopU549Im~j$qFk(a6A<^Ubj=$NGg@Z#4=gR}1>4$>+bG85ACTzJ(h3?5dP$mAeC#+xK{98=ld$6?#bq|i*T7RQMiswKG|h) zhgSRaX;nwZKDvk!5QI<@y&;6f0N!+T=LgXH)nZFsO*`MH7QOyt`D~1|t*l19KoXCC@cd?S2 zgQFfDgc9&%55NP@b8`tuLAq@s*g@B(uAxCZdf_|$39S-QnPJ|AHH5B%A3iY9p$kiM zgf335oBG;Jh*NMFhmzje#l>Rs3njvf_pqa*IL_G#6Haz^or=r8=MIzTK#Ria!Gi~Q zx?WzH;t+XVogJ9d9X|(m<76tBc zz^d*8xR$i<6umU@;Rtfq)wHa;cuEGI@o{Z-)?=q;thPwJ{hRA+GEB-IGAqm`7(SxI zT~ivK`t|DxGBHWnXf^bm&fuhKr*{Cq8h~ClC+DX_b3YJ-A&iBR(ch!4p2P_7;-5(? z8q%Z^>8#i9(IbfP;Ql-`IfK_$BeTAG1$S{J!lAkH+WrYQZxZHXh-Zh2YY2u2HWsM zpaf|7YABSgKnYNfvMF9J)qSLy($*m6?2@aDvf)l+%*WO=ixW zA;)mv_mD;j-EJ;gWqKyAW8^_G1?Sn3LSXev%(C#Xf^e6)xOe?9t9ki8*c3sPYp?T_ z|4fc?Ca%TDpVcp`u5Mh-WKghf%^IC0KQIj8X!r(R$7yGj$;_0rm8`7(H*TyVoCkDi zFtw|T68bkF_>MhTv$x$Y+RfoS%Bu7Wi~nz=&e^>Q=98+&j=k#a+=4C*G(_4x5)!Zb z`X0r`KFkxFpPd~pQ-E7M;Vptv2x1p%o9{)<2;8>P5A7OcI2eW3t)u3H0ELE;3K5IV zU{#>43WF-O zVZlehl%{1c(rgui3~?QR0xq%D7R6K!?yrlMnP9d?Ks_Qvti(ShKy_4IHKWTklc4C4AVHLZbs*5|@kc0GC*OuA^hV1s{Af`kQt z(ifba?;hpHp=4u0_Q5+xP*4-X{7UevX1-zO$MF7%KRv*rF_9H6W&l?Qjv0ELyZHGL zx~}ErNpXbSgn)~qVHAQ!9UY>=fLuPpjl#@({Vo7}rH@ITP@e&#m;x+GEF)0eo&%E? zAA(|SYGjg%rYII5Wh)-MAt2NmH;czZV2}%oWlK!mIyz;6Z2%2w!LP}T7f|wSk*NMJ3KINN)r~7C7+Z~n1+)K*Kly0d+e!c1{uJGr_qeuXrK-VN> zWoz)j5R1>85{;S;GT7{^^Sy|gqIi3ULDbe7TI+cbD@6E}Be)Lm^--+Gb^yKM%$Up;h>|MjZ-gHriszNNK(T)&4B$1Fq`NOl7uN##%ZK=WFT zCtD*}i$?gZI5KlHvTm@SWtvL5`oXxIoo{Jek%^>d^6J5RGbxN(U6=VZcAL`NJ!|+n z&@y^T?^eY%18eI4`22H+{6F4b>))`hUS{TuHI@Q5V=}YPA9#}sFk}wONj*KmnqQPlPcN1R6CnXsj@Ne*q zJO90;5vSlYK&5l%Ms`fC!qXnehVJi~09*x3m4l)MWhN??6)hEhe&G3K6e^%aK?uqN zpi@RI_Vg?&DVc)bFq^2XwDcwvtvI%TbXU>RF5}S}8kg_+@!9ZiNc{KO@02bxe2c!J VGNJ0ZKpu~%dPMVZmXhhU{{uEz3abDB literal 0 HcmV?d00001 diff --git a/content/docs/v2025.11.21/images/guides/provider/aks/root-token.png b/content/docs/v2025.11.21/images/guides/provider/aks/root-token.png new file mode 100644 index 0000000000000000000000000000000000000000..06d4641f5f84984c512eea4aff457d3f0d0c987e GIT binary patch literal 80571 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�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 literal 0 HcmV?d00001 diff --git a/content/docs/v2025.11.21/images/guides/provider/aks/secret-access.png b/content/docs/v2025.11.21/images/guides/provider/aks/secret-access.png new file mode 100644 index 0000000000000000000000000000000000000000..1310009cbd2ce5802f74b3951adf74d6f6ef4c6b GIT binary patch literal 36143 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�~-ZpWx8077S4j)+#Atjl3$mf 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 literal 0 HcmV?d00001 diff --git a/content/docs/v2025.11.21/images/guides/provider/eks/aws-instance.png b/content/docs/v2025.11.21/images/guides/provider/eks/aws-instance.png new file mode 100644 index 0000000000000000000000000000000000000000..593ad85f391027bf59861cab8d47af5e15df4a1a GIT binary patch literal 31706 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 literal 0 HcmV?d00001 diff --git a/content/docs/v2025.11.21/images/guides/provider/gke/gke-cluster.png b/content/docs/v2025.11.21/images/guides/provider/gke/gke-cluster.png new file mode 100644 index 0000000000000000000000000000000000000000..f51bcfd0d9b4728fc28fdc0f8fd7f8de73fd29fc GIT binary patch literal 20659 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 NWOU8Uutwh*`5(wA`wRd8 literal 0 HcmV?d00001 diff --git a/content/docs/v2025.11.21/images/guides/provider/gke/gke-unseal-keys.png b/content/docs/v2025.11.21/images/guides/provider/gke/gke-unseal-keys.png new file mode 100644 index 0000000000000000000000000000000000000000..0bccb344c1bd65c8bcda368af0f67106996265d8 GIT binary patch literal 83864 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�}`Un~xv<~zmd1js;!BHZoFZ~WoNz%bES_xkNyn+Ug|mPCs7U~182 zYF{a7=`j&%YHCp=qfIcpx!29DGe8gQg?+FuN~m26M^o;!J^q(2iT-Jhl?TbGE48)f zv)?BxT6zsrDW*z?C^#4zIu>s$dcxb%(!6m6mYJ1(diS-djV=B_y*%aA(&mX-7SY0L zM5bhSSy^#uM8?FVWM)>y#1gD|4;g=HAPKo^1qU-3KMEUR~gjetf_* zS5MDAT!yjHd*3o5o9Jk=MVA=sA}mR{BhIZL+3cM@(`CM6V%Ie)YBmC(>mUAv~_<(=lmEWfN3iJypQ3CDs0g{f1Mv$C#B zFB#*Vj?p2RE9ciPU53N471aU=gt5ur-_#>t$<9~goe)c_QiFJHCs+Eq%v z!O%9~trNtO5Q5nyJkh>F_xJ6ULkWg1v!{9j`7WlZM#Ia(=;pS4n5h{+qQ-*|$}v<( z+t;iS(H2C5m1strdb2t{f3~@~IrZ&X72A>c>Li5nPl9N8(T=mQ=}1gX3<4_OS_gpr zRB%hLEETS4l}T+JJA~y2Z?pbQbqlJXaM? zO7M&I4FlLh&`fF!(KSWc*r3ksvok{8sk^J?e^hVm&AD4nC7phQI^$I&EjdPS1bi{1O^6TLB9BG75pt)iy?;2 z7G1TXT%a34>-s5?69sjMIc99Z;zf&I^R~IOk(w8RrQ!gyR@Dc)CobVK?Ka~}cd?5E z-D7te+P3ygV)KHgt%&oYq!fQFf^qX!hUSWM3FD?t^-Q8|e>$Coy#&7wlVE@A)yrer zmynjwD_4#Pw~w~=ewvoEu2A1Drj#W>7g~V=AmD~J?R@Xvzn>4`PfebEZCi+$DHZvY?<0!cNb0`u=vUmEcFo{>33+%aA@Wj<%I!`vV8& zFPy)2>(*twwMZ`fF>6pAu`ThTv zl8hNM_ox{klH|c-V-=Zf-n?YNg7&Q8OVp=8PE&JpH8NJt^z60ITXygT)$ys()U<*q zqZkl44p=QlW>w!UDjLXLfnjf(z5NIp&}llplxx9pC(?%aL@IJTIDA=s=K&obcjwb* zi>re-zKoB9{u9zt_R~u#I@9;IX;+nI-Dob4k>lLCa}pcPOy@0H^edj5HWtU89hzc( zEjl`YBQ|ZvYR4kRtvrp=o7l5gPtgc_nvo?58*?nCnrEJySU>4-^=;<=;_nyiI!`4pI3&kTDdZa%=%upqjL?5q{4$PWltI@et)I)^PgaUL-E0eCuXDALVJ& zY@2G$N}}m?$5f9VRtj{T4oOQ_VDG&*zSxOH&D$1um4a{@PI-0tfFbq~`y|+j{ioY4 z+O*ux-oE7NoBOvvH`k@9Vql4{H1@GK4Wq29_;l;~^^+tjofnp6o^`v|@7~?#Y8A}q zsev+30wRwFzC*4$?8=q5=!Ne=#oBKTYQAIkxrTGOh4ufzC_Li)mJg~%>C2Boa~|~f z_m{7w=i@icCk>P`63caU#rQ#L0P*l0D)hJ;17f9fjt_f~AkG2QQ}%$~+eo-@5$^#Z z;aRlC)nx9xbPGq>Z{NP1^zx#oUoSyk>c}e#0@N|`%myonhJ(z^V|#vlgY%frM+DV_ z-$bsW!p*-8Ucmztn}7=jU2JRp(KuF8O)|N4`N}71BnX+Ba=Z>;`bcU)f$T;@!|dlp zckx59{hl%6JfV0A9za-J$fg&;8yUODmE!~Ph5leWhWOFPu#iP z@9KOS*TDy|MR>#EBX!!goyYUBwzp3htCT0>?g}vMDJ{L&dT}Rmh~5;s5Aou8h=52I z{Ry%#L5`lr!%&P$p!Y{nIY6ojSKN^=OJmTN)K~3PUT*uz8N1;7qD5@&KZGQ0IxzRTTv(^&ff3tB&BiOeFtA0O5C;VAnZ``h3Kuu8-aa4R% zit)K{L6a}T#0rIS4Hr2*%MvKH6Q3iL9>|Y~!V5^%CZS9;kI0+inkBSFkV~V#|75*t z=FOYeM4jKn-x&?l!;Dnd0@c&=C3!3iIFev)fJqDfrP7ifefy@6fOw_99uV6M#mg|k z!P9KXnOfBNHdFVtQV;I)_Orym{}4d{- zx$EMO!ghwVX1UpEUcR)adVq&QH6cu1O67x`#*G`dlda?VJ}cR+ANwOIC+E~qPZ5Bl zWo+Cv=a)BvkMdRsF`oF4?y9aldi%NH^85(c-l-?rjN9(jvdYYEy5fn5_N2!bM z?vkD|?zN47T%4!UQ|8K-zD!qpPkF5_AEJVTug&OA1NM^0QU_^RUU<2J6GaW>S>!rU zn56xoQ1e|-U~~uCF4NqdyL?7SwW`sXi&CS20kD~7uS9;^<;!E!is?DW%7rt!yC4u_ z9~V2fCfGRpO+41UQLs`n?hAwVWxxsmMgywkd-swth{4%OQr@G?OhoBFph*p_CT6&r z#EPA=Dr$pd@$NcFmAE+UzO5ocOThEr@6F}K1{L;G?5#F0!>N=SXVKziCF1>5@0eHP zOj(51HiWzq+N^|ItD)#a)5g)^B0Ebs+pvi5hTM;B9*+xJiL{2}Kiq#gb*DO+M@>01 z_QEJ`SdNDxn}Uo54&{ZP1u?`J)9Va_3pY+s=ZY8Y_<$nuRL~5^RJ6bxPp2is{biNg z#5=*m9fSiG4r@i9e(lz7TGwVaKEAI^Om6d)g~!-~X(FjbBB8nYES5m7*I#zG>~cxx zJQByuSr`dQ1g);4SN8I7Fca2-H}?(@Z}!An7wSn4o<{z#@F`~ zbk>{V>G$@Xfo=iR{lYEH*({p(B!tKgaAmbt;ef4o7;)G!^y<~6qkdJIGG(6AuvOtY zd|NOCiERsA3Ph?EyB{_Q+FNwsRIT!=;N84Kn$b1b+a|zVD(8lRrjMee;D!)ePc_{T zc>p8Mu8A~h&na)h$tPL0nKjf*Vyw>ZpXnH*eP})HI*(+Zd^HDs%v8flANE?gHN7#Yd zO)ayrTiOLDT5R)=1$8_F8H?!nXLUgeWL+>xH*YfOMgl;=z?G#G+d+SwF%J%VM@oAhvu#-ylLKJhbEcmnN3b5X?+6TfCw9?LS&D2k~PRf zwGt!0$5B^^?$-K-;^m+67+5png>gY$I%frs#bm<<*Pw$P8DiTG@COU?>}BRLT;c;A zJ`7QiS>|G`AX2}ms{#o6cqz4av zK})04B>Q!BcWLQIwC4-^Zf0ht9}>((@(q7mW;A~LnGI0Bi&Xwm8QIV&MaahefW`DE*vX&98CuVwc#B-s^&|EBy~ z@gu4!fBUX44`S7?4UM?;Y-5)Rp`qN=sg{PPrje_8T*;{)+$u|XbiZ~iJCT4$+`Q-I zOv1x7=z#H@kWG9PW#T0Ja_58Z;hyBeK2Mm?S{a{*8~KRU@bCwN4gys)tj2}uuAcaO zCWnj$yKU6_0jPg8!U>rTB+k*E%1)^Ix^wrmY12M^`XusIAyf?$_ZUfk`}M;wV*ZhO zU`wePbAi}?GKGZItI|TC+p-7cXRmklmcJTKc-G)rBCcA;r=N$Kg04T6=;Y*NpQcw( ze}iGxrse5rX(U-`yDHP^VPa_+Zg)#jUY-PsgJTyjMj16hld&5%RY}Pl&PXCHIW`Xh zfmZ7kt_IjRKI|?sNNo8QniVgkgJ+4(&TOF+Iym+cMMhcrN9OV;@!aQ}3>_>CmcYn1 zAsp@Vz8eXd62}QGE;HEk8wTUSovLA{qVMMzy!x;JZIKC*t7 zGDb6WsfNbF04-~g0!{wTqqMZSf0F4Vh8TYLDH=CIMZc^AMg2e;Vst-t(pH)j&196G zX|dnf?9+CyoakF>*vb^1A@cGksXscxO>fz{)zdcb532txB26^TPhX6wiv#1?ru~aF zHOoGn80OF`?&8IZ7}X|ieCp?5?>iIL(~NHG+jW`K)PH34MhGTdMv67jf4~5J1`lZ5 z3#G5nS+IrJAFUG3MUl^H_Gwj>RYRP0vK}7U?z-vt5 zLPAvjVf0=W5#U3le zc2nmCw{6>&^XIbsm&ePOPQ!`2=SRIB%!mfVWlwI2mo?a;6-4x)t2cWKQ{fAjkF zUiAR27U<0S(h)R(m&SD{of&L~K*+W|`6}kxwZTn+vr9ApHuFZ5+y*v#n<&HvfFb@h)%1t&CwS=a^?iO`^btT@xg=lF$S3n-nkQygHj`q4pj(A zXv(ZB4s&ts`>I|f!;J4*KBJ#yV6~KzynK9#z1E)ATR8rD?(vuX=DVsGu@Sv*#qw2$ z5P&W?x5O2Vnv<&)n)_#}!vW4xc9tj^IV;NhyU{N)J3wnpf(tR8A|X<^)HnvU_4F#f zOmYG=A*?S<2wDYOEYcNFO|NE;e%hP1#WH}P)wW&s_ETAV8)!&GQ(y^;%o!D%_lJt= z$B!Qm_)@KRFm+sbGj^+}j5z?)+z;!93MTP(b8R{~eh>%qIQhgZa_K!AtgIqDmTud& z?dGt^1HR68{73GQ7;4mcwAh?eV_ zyoNuN1R~$CZrx(ey-ay0nIo?tcl|v+g;u_KB^BFCP4-Bu1-)$m%zG7j=dRTkkIe%eo2>}}yY$6Q#Fs%lD}J}N{o4z` z$N%8<^_OW07YEAQrvoQD!fAW1GlajwzBu|-K%4V>zHLItY`q40HoR7&_S|E7>yjs+hR%C$rbqe z)2F3oW+TAJs_8`2obq{sh5Uovvxv$Sfx4lcx^>Q;CT(bh%AdAdpK>0cVDsi)doEyW z8=HIR-ObHysaj7JX)47A=i~x3aF6Wu)-8Pc^yxyUC*l)bd>bO_-KS4iPmQ0IxR*oX zS*+$D#OuhYsFkG)Zi3smF&EOF-RbhnT883y@Fm!4jspRBiM`*KwVN8YOEP-9Garqp zoi5_>B7^IpdYOmM&WsXH#-SD|7qS0)W>&P@L!fsGCu) zU8H|!Y@UOO_z5Jt;jj=075^!gfj5{Xs5(y-H}PwS*nHjw_g`TDX*^Vz%~!RDp-D7Fw+JEPBb&WUQ{H`{{}+j?PFHdu z#XMDFNKxKL|D|Y@$H6H|e$4M;Ow05VTP|gx5b-y~StYVTXG zCd{+8o7W||6>NTP`Yx@*11!qU9&mjp!~X5rv*)Q@5twIW3wO{Au#@S9qKH6w6lr;{ z8$m9|=*0t3B!te3nC(#hVVkw}MHu!pkJ)~KV{5nt=0N*EJp*mjydHm|v0yDF8t!p% z?*+KM%MjtSohRO&&6-F^U0U?%K-q<|E$fHVy3DoX3MLzCn=2)bh9r24Q+XG`3o_&G zi*0^+u?O`B5iNUJ=Hj;ZZ4@<4pRs!K)^Fzv&@ZeKM8I6ST?SuzYkJ$r_R`?>vL_eJ zQ;x;ypw`GHJ!oaZJLpMSZ|IlSn{7OPk4tsd?!f%qyQ4RM} zv9xrxj!rU@vM_zz<@b2pYxJR&Q}8F?;Yunf_6l|P(^NefI4HaR=f$sr*!4u_d3()r`FHHw~|Q$31aSr~_NHUaqqm%4VG zI^KqEnvr}4Bj~>+;sfJ@fAcY3ozUBbXHB?o32KxJOF%pp(J=xriPk&6- zBrC0w=1r5ATajA!-dy>rnsM=m`pY~Z-5 zME5dnd~K)RU#|40^@FlEndios$pp>V9vP_*A07fd)^O{HcFPu8q_4Aw0yQrj(+v&4 z{Vohqt5>fU{HQP=hw8=veLsW^6UKD>NaDfqj1css&iRC%Zf@C;&(Y3D_WDF0vRTdWjKLwd=bFf0QO=eLXW=_Oll_LXm<1C5y@23J!`qg!WC6bSwRzJuhv6JB1T1fqoXs67wzE;`XPSMUsi^*W@g8JZ>D8da@G z!xb@Q9Lcyx-VJgnz4^3^+Vn3+_}X>r_MthWOvhw4B5Uhf^|S#gi2l<$25s?@4)ezV zGL7t6!5g1au;Dt_Zc)_M^!D=lXc%O5{^qTVQf0Jzixv;;&udLgv?jK3gen!$!&6#c zO?fgp!S%~z_)RIbL$|ENl?cHks>U0Zue^~5J9HbkG{QK+Qkwe}!XZNRSwm7Bb8%^h zGEpC13FB2zPr|Z-l$z3m<;{fRtQ9%~n&`C~Hy)rW#|={Ioi9=d!6@rYvyU`X&al$2 zLirTwv25@p);vWbN|^At)mMd9D-7E@Md@(vhW)ak+owC57FrH1YixME&->F3c$td& zr6E_Y44pNr_4NI2+H#&nX)!~%sc@Pl6l~q-#i2j)Y)(JBim}4WxPANf*#5_~^!Q&P z+)wRmR49V;q3)xf8|y;YuF}{4_{&$|>^s(^2x8|g`>O2=C)NbY>NBbwVAUt*tszGs zXj5ahf38JErN1s881P6kb0XnlEXJ)&B1Fo;%_eg$N-aQZ9WbPE$2c+pQ&JX|O~ZIV z87m5wZx?aWRL}R}MM%lYDoH(LV`Gyvwvt!#R6h_MZSNA61?d2~L8A(Y(m=N2=j@2~ zx$;yDaDoo-EhdHb7wR7f8AOc|ij6F`mN(aHPwvW;|U^7Gsy>XRaUITHhqvuc>_SEH^hd&1KPSXDX87 zP4@QnTStwT{br2ZheUcxeo)yf;TM|r5jFhct?XBN# z1pk{wX@BsLsKVd=zjr!~8ddgxq|*rQ6JVyrM^D26Qk$LQ4E*)HRJ&c2jU z7T(?x^pyKCbL3gYnu&66If+D4#Il#i|8aml807muu{%+Rlkfef-RYG!E9o6BLZPxc zCYXtwdNIb}#fv!o#t^NLRZz{y3p0SbUxe%w+nN{-$p)n>^h8V;<>P0eeWOO&RTX+s z&+j1yAC=9%rKGGZA1f600bE8fQiiv8p5Um!GVqrb3g?WlLSdqUnn#R!^N$sZwg6;( z;>dHljOf+s26H1KxltOZL~SWrFrXrMCsc0bRIkMqODaqLhH)RAb7#z2kiAJkhDAGh z>eSrt(+17j)1PUMe7)u7AFkn3^ui5A^=No=TN`upveg4kar|L1utk>SRuPHNfq{~- zD!SU**Z3G9S}L|qL&bxiWjTK_J_9TMn5Q7@NtC@eZ`~T34v>G&cs(?vn>TMh1yVRv zM>tB}rkVi@`cvA2k=uQylD6R@!wGI!oj^mxNakA^&p_a{-(Fqh&V=+@Z}k8Z_Nz#T z0p0c_x2swPG%Z+n;kLxA*{es7eFkB=##ToW3k7&XYWzqo=3hL@E;la{mQOX+3?B-X zhm5|f6_V*0B|9Rq$o87$k9hPS-j1j3>gLFtyk%7Vobkf_s1#$>70kd?$Ir}ud3B<) zwTBV%8&GbtMNaU-gch}2`RWIIYu=?uH#e$X-&tdV&PxXL|r02z|*A*psu} zA;RrT&>u{>fLRpsS`$HX!89|(YM>Ac*?xvYZ;AhIh^pr8|7D1RhE(46S^|zX?%jn7 z%SqULb`G;13x+LYZt&)q%G^H4uA6!}j46UAnS!F8V^Kdo{}st+kTP3pXa1ZJb77YA zwB%kp=5R#Os)$203nYi6Flf)$A!U~Sk(W>7Rsg?dtWtkwD53@cKPlt{V)_V+y$u-) zDxX5z0)Y5;(%w=?{66*5qRy|)3y4nq{SFTa<8Rt5&B!ek_E-W;Bla7=4_!_`B?k$Br2@Wc27?gEtv+ z&E5y8u{GIA!b&Zwq}N1Xl6&?W<)^S?aVfL{$o}?4IkhzJ5{-j|(bSKOod1qx#M;6- zEGKM^O64z~pQ^C4jkZP+IXViXouh~Xngie?(Yb)M1;&Am=8Id4Gpa)KgO z#&9L#MVkbjFG_JLue}{+shJva{Gcz_2v^gX%}gzVA~MHKj|3%jELx92G*g$`x+p^~ z;;}hZ$*2r+?NXVZ4VvmCzTKc%=jo1944HoE4hTl555lF--VWd4D?)~-$4_{8wA;&< zcboau@48`_ZWLL5flIwEHU5Bh5t9}6qJGFbeY2w+pEP;$rc%w7Yrsw1r5FE zSUqkeb7LXz7*EmF*aW~Qih^*Hau0Ag`qr9}zvS!d&Zzf<^VWh)M9E7l=Gx~8ye=iz%KEhRN; z&-4qsYY!Kdz>_nHa!rW8_w_p$D;}c_iAE9Oo0EWZ5xO$Adfn>nxfWBownV_xS#R$w z;GD=9zc`GA_(Fb2+y>8+CPbM2-O|QDGxfT`sLd zo)>dqM2ujyjZ^*ldHEj=Tusg)l8WmlURhODhOnLy>sDixBB_9DIhluK^`pG1D!lGn zhV}lNO1$@3EnkP>A6))6l7%A9b(o=3e>tTvEsOmC%?BgQ^NMvao7DSOt{mqc3DLl% zp0cuTRKE0OQSuYXc-lYigyO))Ew3i;p#IcgecA?iPIC;gn!vCAyU*>Yq>8hxj1-kID$M*pVqZX#97Tn zFsI28lA72i>Ak3wpM?_wn>k(K%h)WQeIrB~AAj)2g$qyMT7HCN2ZvJemun>nL=852}x{k8#bgs${3P>!ttk1a&vWpvf}kQJuIRPMjf_|dir!Z5qTGX`Nfr|%FXI? z%f>Y9*~YIQ{Et)53(q22f@toUO}^}3h90bBqTf_*ys0o#A$N zhA+QI(RLUN#sw}|1@*X#rKS4*&xFMf>WlT?78dET@3b?VpOE>;L4g21<0Vsa3dLj+ zF<}iTC`=__N&=7NBr3mt(XhYQTD?QsxpPxux;v5yN zKxr+s7Wv(Hdk_aMZmQ3W)mlzZDdy@-$s-$8|8`GlXz1=KAixmX=W>5NF|*=t<5c?T zG5J0?IJng?GTC$Bmhf;e=!@pulApFII*R|cO^r90&y!jEwXt7pH6M|p@~NQ;3fiOA zJv&t|X=Dy%p^ghcg8<~k(XdnN~+{|pu{RrXCb4>+3(;FAvA>HVVySuwavzW>z z&Zj?ZQ#cH9g5FqBu=xl(P-4Wzc27xn6YuuHW=S%^Qj3bj)JYN6fH5rlQ_1%=3J{?j z2f7iXq!kPW3y^O%It2ixRlaiXpVq12CDk-331=eaS)snJE)^CBHtuX^giUv7Mr@mQ zGS9gP5Sz5i$3hQWG{e7PLY|3GJEf!^VjcRD;)JkiUs75s%t~Td9rg_Yc7=#eJ>^ei z5+#WZ`PzFsyxSP8qI+iI8V#fv7S~FLMD!h6w?sxH5D;bMGn|(gD|dIBVVwwY;mp7Q z^)lGBnWx6QuYT%n)r%X2VnBIu>Pat}`0>$L#Z{ILondde^JBmnDO{S6rXz9b6Ey+L zEON%gv_X78+Ic@PobCJ+nJN?gDv{aJ>X*s_&KO@pJcd8=8+kU)6W&rR4!@CK-47jF zivS>wbU@yl>gp%#){t}SSw$i-MBG}a2S->DVh-Fwr(-YMJ!7qH8nH-2qg3$SC25{V z`>XWCBE_6YO^yw|O$nT684Z!9f}O=fC}>+TIaRDdVWEKP-I9OrURx}By|%0}FwinG zT1IxB&Gkd2dib&FZ{%4WEBa+vj@_UlYAqBLOxQE)Y;IRbl$;yf?pt9}tUYksjNFtz)O5R_c z%OD$ZMd40^wi8X2G?WC#zM}Bvhdlykv=Nmz)?F>vfw$u0<+=a;N)3-4K75hu;-`Zu zJu?#(j+B^M$9&=8q<$4%@!1)>hq_CPghUrH#qNio;n>pZowpbX zS|8jLapr7!cF=JR%?k$oCK!r#S$u_UrlzicHQbZ3;pEbIeKroDl1_ClL2~?WYG}UW zP4c~OT8jLr^PXs__o;u(Rh9PL98>XaTbM_aoMoW2PA z#wpvhq9Wr>OKL~rM2inpw1^ooJw7AwLGq3z zZp+FGuPAA(^q9#>kc=44%3}Q|F?{GabvVW;^<>=wcZN%~#2QrrLB@F2f>yVsuMMi2 zpGA9}`rM7^6oTp!s*ad&1P|XMSX%M)nKMCO8bqo&IFROwqFP%V@sms*{3;9L9lgF2pu!7bPy(Wy3g*BLiHO7{fUJ-qV*usnFJ6d@RH$uCy*bkN zRw(^i+t85b5f}QGyS#5T|CxKy zn0h?1gX_9prv_*jD$P!AzifPZT66S{=^-1crqj&k=UVx+| z;2b?xZafe9;HwM$S6GyUJ1GnO9y(K9&y8Eft(_w@8L?YZeiOzFz~3!=pWIWTNsEI` zcaXNI4s;z@!NS3|SSrC-xXqXAHCPh5zvtP zH;$$#SN}aVH`fy-c&t&vIbUDTA0q!YLpgrWQN7ix-Han*rCaIb^GUdRanDhk1Z&A0 z`-=`ta*^VFWz|2{T{?~M-90T$$k5XFIYT|yuUvg|lZR^9E3J;@0}X(w8r(>v`2SKK ze}={30xaf4PXZ)+PUtgUde?3mGhre|JLgx|=Juy+bDZE>R2XQ%UlPt?!bZ8^#UPc8 z>y5lC#m4*Gjc2#|Ji-Vons6W#*MSnj>#qTmd0V@bPtbN>cptSybSS96Ujt|`%O-7! za5XS9qSph?bG6q*dHL(ldQ`JV8X6kJ zlAtJOX>%xT(Q$s%$Wyc#~jpg~z& zAUjLkm^b8mE2U6c5)Ubwokf^9Fv3qOgjx{l%eYgmU)8$Te8IAE8OO?|p!|vzA=>Um zqe>dBR>Wq$Ynod139bKm#xocW#a*LTY2^M1dU>w0dNjO0$+b)-{BQGF<2s##L=_U#WU6-5!YKhvRE{%DNjk@Q>h=HWs5D z!@k+gw!e|DUzc$lc5xFkO|kuYz;uX2>ZdIWT00sJKNV&H5QS*XSLgCwgV&{%l~!J_ zM?@X8*za{WJ-XN>C8Rva++)$Q+hjc*NkB{Hn&i4c14o@g=TWlEwyCdzaK9_*Dfs~l;&?C9C+@^U5Fc>F zo878$ov*8lgS{h~WFF?oS2>39eZDo+*QQyXo;|WBmk8SPgwoni-cMB(9Ks%6m7dLySk!{I-Q*RRGfbDK2j(*{stpH$p4BxRx(oPb zQy5Pqc^RlGlNF~#f1b#l0yqF2PANH)gdT|Ali}kkscHGS<6|6tiZd#Dd1+Q;0fWMK zr<*VQ7K`ueFZ`+{I%9!*0s;ef10Wv((B-Pr9eE)}iIzjg>L$mUbl(y@E6?*88^6!u=eJy`bcL-lU2RReYp0^;-i@eeLASa6hYf4LB9q-I%s6YbRLh3j#i z{&oDgwdRG@_ONga$geGXn%qtF};C7l$)pV^RX-P=}0Uu@LseY`Osq$Xh{Gzg8;yHEG(#nZzr_Y$N4o8)SL8Yj^ zsbV~wFM(Ivx?lY3TTRs=8cqJ&%rogS*XZ)(LQ6|aeGHAbhSqt(R1B zh%hPOlY0#7-s31NMr(wEmv4>bA_hk`2CYGcJRj_ilgG1rnW&c-4ng{^77=z#PWkh3 z`w8mm9unCI*0_$h$pi}V&7kT+fUX=>fEb_AWlhT|&ejO>OV36bX?mGhU_Z;9?Epe&Pl#e);k) z;I+Wg^wS{qntvQTW-uyqVjrCv^^8Vp5%`D?c)8ypAa`dtBm8DE|D4|MM_|H#F%v7>$Jl&~C&1%Z646iIX zU?*B<@g)LCK7D#)a?{VmOpqDZgG35y8_N$m69;=HoAvxP??|$&NSk3@Mn5TVN&SjT_27(|f9z>$NaZFTBGD)1AKOM@J-ES^QS!WcY5< zvd{TcZIk`)`1o|^GV1ZhnYag)F3|&i_~D05PEMKzAxr#&+xtgE*zTx;lbN?{S>dx4 z`FYNf3mNh*y>k5eb0LnsNS4BItyy!=T%E|J^;284@6;H_$|Da#v-LX{Bp8H$q=?dV z$rA6}kV!dVhBN6|Vi829SAI%6Z#Q(Jy z<_-0!HyHDQj3@&Y_|Gm8B_JFGC#1O@PB)(xlEp#|EVyE2X$gL9_19krLvHe~S@vB_ z_cG&*#iQ{QcH|$djMB^FgF?_zouro1dn1Uxq~ja>Qwo0_|8;n+%K9YqxoG?Er_kOCOhw9eZs+;qrJW#r}Mb@^Q-tk+SlG!(|3 z??>fpg%m~kxSzEcy0~lC^=YrGD)Y2nM6w19>IzuPvuw-FU*EM!@|{3Ck!Jb6^73b0 z3!8}s6?xBIgRHLRPO7V~a2X3D{qt^r?d!ls7lB6$zPS%Lc8*EOw7@i`zP+TdYH~T zFxvWQ5v9#Gz#{4x_v+6hv@7CAUkrX(W7`8GMNa-nenf)Ty57=M!9OfK3$~ z(zYA+Q|x$p5VkMyC$mQ+9Q7hEiZw}3m{X`Sop7y;-2HUZ z`*=FkI!HwVIEr<;m%TqUc;dw6<<5#-x@1?hRrGm5Fah%!uiUy~WAi*v>mT`8d&i7? zlOOTl46cTw|BUh~9`HZHyL|sgT-TZ@NB)rrcBR$-gCDFYbtb#v*$nGF|51tUG;iUF zz_Q_KkN*hqek4%s>T-$V{9AZdu=AgxV|E??88dcQ=Z}8|i;evCpCMrXH$PaI*LwD> zSr*xKGNP;cI_)o%tv&9!Ss!9HZd^_LG&pwflKlSv{vbcTpP5rJtCzXc>A=`lCt(`a zmz3z7XtcB#L}UAphjQ1YS1m4yp*Cqhl$MpfKzdg3p=r;FcBgamP0ob}0xqUCJpI(2 zv`GLNv2EMjcw73-tWwYHp-%!7N3OA?taH5dp)3r$@f0B&#ln92JxM z*Ab8Ek9J>b0Jm<1?f9Z(tf$yjELhS7AtyJr&s>Rq+QIU80YgplG!E|JV z0+;@~>T1i6Ju@mlp*xf?U@i=rx2a*#MrHb3<0B1Yip$G$jmNTE_Z>XQN`6wjwVYd( za%vqgy8<>m4-1fXK?msgp1*iu@?J4BzU2u<`9Og(3jnl0flGf6TD=U3=PYvN_b^;+ z@@QwIdp8ap?B9Qs{@2;G{7CGifjY|gEhxbqnGvk%PlrM=)>qaC=_2mD;rZ*4nr#M7HjCoZz;TC(vqG_V&l?c z=BYnes7WK-CQOedvTR7==PNi;`9DwdimGB>Br#ko)Vg%XK2J~ zeRJk|x3EqT0Xda~f(&qqyOHilz}c@Nk-GnPR6|*7&V5BKK?IMq~`WTi2*}m&=(Y6S=7hBXcJp zw^M90++i}csbil$?K7i#GT#!ZGjK|KxnT~NuBqRAlE8jYU?C1bRTL!aj+n)&7WY&M zNg}7>IC-xDx73gzX=T1GH1nq@`lVa9R@>tJ`|$h_F;f5TiH~eHtc! z9sc5r5|Xbplhsp{CSVmcN-)uv5fs^XTA0k(U6yk+a<&Yu>A3>}8#K=5Xjj@%2F zOHkshR8{=)`C8S$E9-U{+QxZe;%T~;WE@C|*{~xDU!Y?N$s1nz)`34&GG{!ZWZ0Nh zjz?CC6#by$@TQYmU7-G&O_DN}YoT>%;3;;4to_r?`xAu;h5$CCsA+xdQYxA{1YPf| zKbJn=)BEsPlUohw|Ua_tsh^t zP_ct4O!c*mOK9vdGJHvXU+a+IVEIsl6?@A2=u$>7>4cRW&{{uR+S)#Zp7$(wiaWtb zgg-4Z0uAe&0Xi6+)l~uEmJE7hQKCI7O5U8ItE1Ca#{bcDfLsiY+7D&L3z38klp^K% zF%k2LWlHS^D1ARQ^(+ItAq$jmt=)gGRFk(%Yh8fcULOjFm^AhCYktDiw+ z=QTXIe_zHG(qS=A*iz5LWbiPAVcjswkMVN@B$I3-j%mJK(P}!sprpUX^60NWR=ACT$OyGm$~5JcD`3=SovKBP3N?CLq4W z%5(B>In3*OOz3+m4^tfwn z?A*TjkL}y9wp|}N|I{mP)sHu}j{EG=7?etmT4AxCZ=j7FwdgF&Dq&ViX#-7Q0(k08 ze(u>bmB!6mb;X~Lr}X2rAsvyCvp<$x)6mcmb2rQXOz!)W7s4S9(GK%>Z@O8$Uc2OM zRBhzGFvT){m~wsa_&$J7Kel=OXHZZ}1-cHDen0c|ft(YnHTw3QWMR{y?Ta7Z*YY4l zSd{9cp}p^(Y&QreMi4GCaLL_I8#*FNvrVg3WU?M*muNm|VR+GZ-<+TqEKg*^hq)0D z&bMmax*tQbN%@eogg2-bA26yr2<{2WX)1+tM49n;<_&fWB@k@!gWm@XC`L|+ssWhn zH13Q^8O1(<(JesY)oG*AH>4EXK~?rg;|`|LRF_eBl+7$a>&Mj*IXb>xHgCMf;4~f? z(hJ#37nUh}lz>?q8s9a;kt8-h3W+8TQQCpo?Y1QtJR}dEzE;v^xbkl~K{BVUxrCs4 zwEUynb)fvj>%33RsEAC^5No;Sz^BVq39>J->d9&>bC2%K8P4XM=dY_2S;DQf1BcHCd!>%hEEI^Js2WA{$41cMo& z92xF_F!`g?_?W^CzFDT&G7q5zQ|fy`iNy8g%ZoG}FK8;ZVN#d}b!PJVG065F>?^vu ziaPG%x)Ln_9L^du+^#jr3X5Kcggb=>lYjo30zbet*{1C6C zidcR&T?-FRSQsi5!BMmuzqF*>!?`$*Y*_y1(eY7h&&OZqcKT3#dlyy+{5YwU3$ae0 z&R^P!xT_xwH^ZkqQ8aY(n-gR$W2Rp{xp=0-@kT&MA)!MkPbtYnj2QJNVtARf6|gYG zRODpzH1RYD(Br!JX`gl@2RbmY#Wt?GF2f9_5u3)fC8n@s z$0&X&&tK>?<;9^A%cD@yv=Jz)nZx8liGo8~ib?ndo#DLjTc~Hj-R@BvrSLrTqpiEK zbedW>Hk>YzwR@n(2$iVf+bb{Jx}JFXq|=pu6*JTa;9##}qwiIHnj7rHhh)yME!3Sz&|5kMA{U)++_E z>w|%0y#BTD2#~5I8eyC!m*~J_C7q@I7(8XZ)lkDxE`OsJpXg0Dye*LEAx}q%%X^$L zY@ka#@t#O#FA-*lgv!j$cOrSUCEXI{_x#nl53DA&z~!Gbv1lUX_PCUyH{0AQk7p)x zd7z3hV7|jXt8X1(p|T;QimNJgdHe}Pr4JQ8Ec&+=V6XBIKZu4xLi12p&RaVFHdP8I zb(0I-XHG4=j2cWii6uq?!{D$Yn}kNXD9KfTfMAW>#-Wn%c z`vr-hi!AR^gL`b%j5_T^?En>d*IfM)osner@W2G1rp~_$X1=G7(_RWdn$+8LDKb&J z8^0VEljK~if0O6Q8Q0XIeJ_y=KRh%+3;C}C*lMD&>cCq8aDZZ&pu?EG<@InxCUC&s zs?Ou?x%DJmpHj zjXQHsyX3FU-W5LZ!=`5#ygjUnL(;hT?!LBHe{M@x92#&aiF1Q6?iWO;G^u!y^ljE) zIFpa@O77u{n1)7C1_#ddEp`F6Ug+$q%!~d0cH1ylJ&|HoKDWXBs6ZCQ0hPHr@mYvB zCEWt~Z=BIX(Dmk-O7Dr^h(+Spb(m3qNgA9`dk_G)WP*}GAiX#iv+>vY5=aN{Tl<8q ztIn(a7-gL>Dw?T!-o*Pu8Hs`#*}kTB(`*z5Dv7^1#r3{7VBF=s*?dat4O^FASv$FW zMlR+<_3o}|#~$TH;?DlQ6f?Nm=@_@{_+)sX5JD=Vf4+`NJc2xA^>;`@yZOLR!YC;h zF+Hb0E%f7_2w1!)YE*Z5PBe@lHOayckma5B#pU6{i5Zty&n@w>EIQS!t4qji>mlJw z5OBlOqD=NcEnryRi(-Yu?ADFQ;7DPKc3LVIK58Rkf3L8yM}IS1TA;Tk@9Z3tFgqV# z4uYWeG^gFNv&I67sjowaL_zlS5Zz=wDdi(zl%M zVBTlL?`pX3V$+y{b*&)}fb;~W;Y!7lM=fhR2+k;&gJFA~y2hxnx>IWw(5XuZcd zUaHCJ}vE*)dJ zbwrJX0=v=>589 zKK{Sx(^!m@!06N5j~-pE;r6r5+%P@ggwZm_iE4^Ahe~oc3oPr{qkH%6RYamZR(@eI zW!dPJ!PhT$x#l;~#c0;ghY*4Cwy;flG(UtW3gSm=@i5rJ0PDATQ6Xug@-jOl=H@Ob zw^*s%@G$9t=H?|ktl|_)oL+Q4S2?9K>eTTy1!vZezuY;)jS&#ECf;MKu1mPjprpX) zwHX5(U=iA7nzm#d2@TPa4x>ak$8;-dP?>lLUD$8JjqrVz+B15`f66xW9KPXXc-ACs zLeX~#)ei0_IY|6&Ei_OpM@;!QL#s|lL`0<3tAf3o<(r8IP=?uy+~RNL*Dct0G#K7# zay6hQU|p6NltXD2qlg^IXUyl#3vJ)@GQW*6iIBC10w4EbgPJB=<%OY~?*CK`6D zy*Z6s2Q*!)VtS!QyD~sG_7~Ja_v0Hr4daA52tX)diWc#%jq6n6jBFj2x@iF{nw9fe z6)QA?Mv5#3lowd8y=c))R%2m3kh{Z@?!f(OD9FrSFb?HridU~*oxf<&E`%z{{*=cB z1%*9A?{s1RFkZgP<@diG9};;I9=!Gn|D;aXj68zhisW>=lD5|cgyJ&{7ePFCP*gk@ z*|)jJ)^B83y#Mf>zh?O=Ym^lyO2q*bDHk;7gB`-c)BjeaJ+%%!!t$k0%cp$dpwqBgF$Oadwxz;nZQa--k|_rbcx=&68~`x6 zp7Eq!CfIF086J|sRkzx~-_pve8*Hs~zkG9AyW!SPR6kc0+1fc%dADh?V@d4OOs`*> z^cp*#{);TEYU7pa-9_~=cij8tymE}+?&M;NFzKql!>dQPhIli+%Wi6ixs3OX&S{^NDk2A@ohmu^{H^vAyiX=67Ag1ylzgRpu0Q;;_2zk;-~vehC;d$;Ca zf;7W@Hdb~zWb37^+O!p5Syr}a!l;MSaVYu@e?vf#c)p(CC2+oIjsj>Z}g(*{2jEx`YDB ziO4Af2Xqfi1Nq!YB5)|5XC_t8@loF=;u(;fNiD9|?I2OI_>yTAi0VulIx+UTF5TBK2_Ouw{Rs zLA&*=qIIiQ^Ac0k6x#^44OMd3-(Ms$kocWCcLrw<&U|ZRcxHal$;mq;K;Ul?TE^KI z*RlUxzANK>p`MbXY1YN-zq?KEgZvREUGkM5DGklY^#F@e+P*69Mw4bOBy5dwT}=N} zfK=+#wKI^6W47frpj#Koo0f4Ly|=uZOtJ3~b2c}xkz$L>H8?z6tN^%mxFS8?yr$w4 z8QM6<4jc-4CPUX86n~C-cTX>U7(4tDO%Uus0gc-Hc?c-kM@B32+LYrza9*ekwFMUi z{n8!1QIxXg=H_Q?7anFaf@!A{7woIyo--nT*4V|1oxhd;PTqnCRNX`W#fcq80CYY_ z#DtZ;$GMPgAZ1#uCuMAFpo(6c_{4z91iVnbaRGuU)M%1K#JL%E-D17i>MOI`!qTsA z%r0M#Wam%0c6AzAyi-P1=PR1?0MFKCkG~MWkt&04DaZ?)@AcAj|3ZT#s=h%vIyt5b z25XHQv)-6*AeDTwgFWIu9#B~HX?2*!=d2(0ZWD(c9(h_f_mxT=M=zpzpb|mKKlEtf z{-E+LUYtI5qP>_B5rn+LZjxma-FYUQ_uID*RALHb+~(hcG!zIl2|4Do&24=4%xuX7 zKF=;g(9n13cr|)ujMt^kGYw6Y8``&Pr)u_den6hT!qMbMR(AeFyVnT5E#oOBId=RpQ$y(~dUZ)1 zL*M~)XsUV{@6d^f_2qLx^T@C~scv^Yn>+Fjz3T2cL00d4k|b!9-wtX@j9pvUH0$+a z>s>;!$aGMrcpz$LV6)v=;e4f(r_+^#kMR>sLcA2)M@QbjUc{0+beIY3O3CMzQ4G}L zL7=OW(5&^Yf#XDt*XMjOnyF~K2R&s8Mp%Yvm)si-{ zKPiHi-#89+g5L)lam(rPN>k;qVFC!w7t2Q@H_|CsBdE*0y!`Cdt7{%zOH3@0;YiZJ z8*kFBxt0boD37UIH$iXbx_on=|6&}UO+;Sc7s2%H6q#B!Roj|06HrZDfZ&lmcohls3J*FEhOsYX$M#{Ii!JE?!zN|Nm<@-oA?XKNT&mY z1t9rjAT|iG42pp7OY&n$D1_T^V!H@XB%pw+6G8qoh#5{1V5p`u zXWnbE@0SIw_k1fmQ+~qiTO)u6A~YE`ApJUec7ELo0MX=)G|YEoh0@e|kFTBHX7}JV zai8=qdyP{WPO~B>%-isq=)u}pRC#s9aWzkYbtE@5gQ<88YgQa=t$l(hRia{q(she> zH3SA2=F_XIi%VmR9e-_Rj7dy)k^jF zWzFCPE)9X^|B$Dlyk=OX>l^`!EPgVbMa|dx$HFG4`{$cOlw+)?_0!atoA|5 z$|E*+eua*X^yrDg9>Q)f(Re@r7S*5c59-k2x5msy_=Vdca?A}~g3S1%Svz+1!H_|@ zA7b*Ei8ZZdj zHM6J_F`Z`aEjo0|_~h)MJB4X!6}~OQ5_Wn8f*L}24jeWNaAUY>awkCDAzsb0|Gr1^ zR}N~})9A4^aQhi6D=W{ghqsknX;I;3fmY#wyH~bb3g`~vtHp^gtd+x@b1df^35;F3 zZ0VyV<%z2*$A;a?Gi=RhVc(BlZi#aWysnqu!Fm+hC4Pccd(W`?&%3O4T;_tl#H}nb zu(Mw6?Qt75T4456uP0jP4NNSY4J%>BHDe-1Z+9|@h>uznsBfup4jIjsHMBAB(*}ta z&C2tM{^+3j!9&6y;x_C(u%U1G_?dj#C0ExEqWHLpbr4I#lb#z>Zanqv=&R-27>(Y= zxAQ7Zq<~oNzB0GSGD`ces7ueCI*v(OmRME4;X!3=JA-e_JhhZ^miM@UH|fXjCrNooy>?V$|PI4hGUlwLLX3#R z(f2uU1i|8zeIEPvrtYEym})TIeYxYZS5{T_`t9yxyM6oj|HcsrC%!D_l40a{Tux;( zlHsVqNZ@F6eB$G-jb*DZoDtGx(*AE zTC_>SH@=+Py1=*~I(qE_rGHF+oYt$n&wocs{(q9Dkm& z*G!i_?L}4Gf2UpkeA@ABt>=HFYX5JvX8*@e6Bc)qip4B#BEi`M9{T?8a=~(*>*eTK z|M{@Rhr+Ym$2|HtO~=0DBr3vJ$tk|$8nYhH7hoGpQ$gsb|NOgC>e6$EQHfYs4OJyv zWa7klJ^!xHzU=Fm_O$m@2bpPR`?)53G3Yb>9o1`CT2A3oQDrcX{h6&xt>F#}8A1K= z(Ny}3n2Is>%xH{ah#z_Cpo6Y@dDBX|)Xg z#yAMsX}e2>AU0f?$Z?dY)`whSK`4llXeM^fS z+o6(CRI4;RfPw#~B8^ZN>8VGd6r#&Mb zY;-~&Z3f;6_`)LM@}hWLIXv37E!7Z}%m*^0zwRE=cnFK7_VtgCwZ-zR^R4bsMd_9f z%?9WkH~&!7Cke$nq-JhaTsId*KnT$b!77TQTnGh*q@Yy$76G4opHC^2l|+7_Td`3U zlP&#^_!$+5i83}mnHvw%0gRge>>7lM&?G1lU(l({omhVt3#RQC=cpfCXPA7Le0uor zb5E>-(+!Kh{tc36pzRFh1gr8-P7+Lyp>F+Cav8iN{x!E!mMj0ZbyDd*O#mRz}Tq;wL?@+^-2c>nmWZPmYB-f|twf&j&`{Kjk1E@T$ zm12lTQl1^w0}Kj=bFD}k5qKpKH755A*P33=vc}%8Fe?H7f|)LGTY?CSgr`!yR`VTXf1JBc80_rr%LvnoU1#+V=fAJVkgSv85@b!iN4{jN(Jir@^GFr6|M zlH(!jGE&U${BOE6Tk>EKSWFELVD!c`((*9hA^s9+0F6Zf`Au3imw*^0jX5COlsF0) zkYldTrSV0xzwK&|D!Kil3EX(dp>mtfwdu*`PsD9T?;&B2$WZWJi+%ahR_Z9(zJJTo zm_)n4%NxZNd0gynS;I*274!=a1&#qYpe`;$OrsmE0Y(lE0TJI$WN9(BWi$%6|CXgm zTgereybj0}71v)!?gOe9;}J3etVzr3oi4I6M$NAP6&OeF@m-+SAnYZ{d`)nJoS-Gv z@ea?a{7RWkiSLt8)v|f>wcv+MRWa#GG=+|ij&Ee-d9Vi#dlJ4L$Jj1sKQ^6&wGPyP z!cHcF!&hkYa<^aokj=_VO`R?EI-jURo17ei94_}yQTtpxR zEq^=m0U0`Nu4f|07Z03OwVIw+L}4(3)Z`QgA^@W$rr}Khuwkn!sjGK_ghA>wm9Qz@ z8U?(Gna@V?t?alYXp|waDdG;Ja%cN6i%o_!fnkdAj-0?*bLXyR@xWB@>gDf%X)r5U zg+7a2eHI+n?A{nuM>qEEv%BO)Eb+@l64RSfB&T?07l+ zcFqn0I)u?$qTRv@t|S)BZv<{Ck(wOHKpoa?%=&ZlXK1W;Hmvcc;93hMriuXaWOzvm zu6suq3YDRYBXWpL79@iDRA_o;^|aV=Ya4_Jz#fU+`rZ=}T!94!yp9;g;77{UfHpg> z?vz%Ptql}0Sq z$#l9m3>Pf81D@gdd{1vH>5(d6d2vhIAAeM>t;-uVrEUUSP*PIZ?s~-+;Z((eN6?i=_VVbJQw%dW zC8zV~IX4k8KZc=gk#DTLVMKcQdich4;6>6c?9lKN?N7nYh1dUHG6b)Iqm?E1|@kef2%C{43 z1p~trXuQNLzxS7ZK9O~m4jF-_h8R9T$I0+u^d9dJ5)9tlo{fIVDrYESv{;DPugFB2 z2u|*q-A>^^7nNcp2WBa0$;qd|_)#>m3A%?euSERkbHCP7ER^w2OJg7+QJ{&m3cODZ z>^>mT>R$~yKQ=(e=dRT7H_;yn%n#943SW(*HP%;)*JP`Bot_1{t##&F|}-jAfC`k_k$_KFUaslW$k z2r-|mGa_?*a}|Tgy-*w+SCWiDHHj)(xH0U(H)>&hE@1xz&u#Jq(Kq+3)Ncayu`f=( zJ-(E3h5wULY|sN!moTM0E-15@sVDCMP?;M)pyXCaL$m$n7#g`X+P-VdzxLtExr+Mt zFCtbLKWW~%`C>_F*)>}wZCz}xS)R`9T8FI1>t>~?)L7fMJ*um$R_W_yIyCs$wPLR; zC!3b;ZZ+`7-+ZmrR8`|ACXPOO*n35*H|wfuzi#^Y>en)$1N+kN87);0%O+V{hpw|` zNFC1E8`akgfa4@Uj;)V2Pe1mlfMd*_zxi_}mdpbngd()1i1V~pWj+}%;JqXdmp$ku zR(Mz#h01%&7Z#9QW#TZ9%ktc;-xoM$$87LRN={arsyk%6Up$ z3X<)Kl0~LYVi#9!{+zajqVx2$&M#^Eg}mVM(D+&l$rXHe3?;w%pfhu|wC3+#?znk# z#&t*g1GN^emoJZ?uuG2LOtc3Gu!rTZh!B7sP?FEw6>Y0Sm9_22qbBE!;>G|5E-u#4 zmNmx&Sa$w1pvq@F7tb3mjRzR|^nmZLz3|BPk`0dw9IlSC8vXzp(DQSrXQ0>v1`L?- zwTAtqgHVif)`aC~R`ZqLAoPW5pP75(?*Xk18aPn3+}NJ%^--hrXT8!t&?-!Y7OaOH zfgJs?ZkN#K(EKli)&|3`tBk{t`BnSU;YV z)Rh6>3JvP~@l)`@B^*cUK8^s6lGYb`=SVn(xMT=p@+u!GotqFE{ZFQD9fshL7dOaX zCTvlupUkvb+$A_O)|QhM#qI%m8tfDg5nRA6v=$8-C8RjC!ms_6%N_l*-JW#zdn=Ru`0qdHU%e*vOjHrKSwZ#D=qz|2W+I zQD14)#2n7NuS?4|Z{8d*rAeE~Ss04G#vVBoG;k12ok%FTsC;x(|2(zj3kt*+fVG#e z_!YS{`a!=cjed7-_XB#+LtM@?%A2&fGx~X1S<6W{z{PUXgjh9W-ZLWprjMW|nU2Y) zqll6i*e*p@9KL*!4MmN$E(&y(i^{WHxy8AgwW{>lK95IOg`WNfnPKthWD^b@?q7e> zX!4?MQdpuQ|3g3}QFnrwQ_sk}QtDB-6(m3NPd&RJk^5rP-ikAZt%!f%suGO zW&zf3wtG@BH-x&yYepgbO9$dYNurTxNQ0Rwl2a!Us@a6^0=_UDDyrYzN zDZeDp_mDt4o30fl-l7NI^12X9PX8LF<3GU*kDzWah*_h9hnw`Xm%N?e|KIDcRWq8i>%4w(JXqgS>-)`Jggd)28iI zJAY?>&$hd3jZl|y^>w488sqoCvd#tnhR;ab@Z$?KEHib-bksgzCF7qA!U92o^!C)B z7`xGpIc_rP8qa}>^Ds(6Cp8h8zY}PU?5iZ3M z(1~d|@|O!k}xN8OLD5`8)iIJI=ax<;uWTr-*%c|F4<9)wf#@ zldkNhsx`dwqTtU&;q?F8Smp6;G>D3vRtj8kCT!oS53H21ck1 z9QX{mk{mri7Yn!T&3TMawp~{%CBdmnJaj-SGEox1i{yP;5ys@qt->^lX+{ z=S>~{tfC67&Nj3aQ9jE>LVi?L-<>*iZzGd_C{ke*57X4nn6W$QXSd?Xx&U`Nr2_}v z2*vzYaK-LU#b(9``C4!0KW{tL<`V~*35P3v8kE|iz|Vc@705Lo)cBcE*T=3A3p~45MydavFrZ0xVZTNT}jb4GCFZ&C#x6(QnTIB z8^JJ$G6Tz^ewUQBBR3O$HC}8)=k+Bfb-Zqt63!8dQ|ds)ahonw_ubBip++9H;kBai z7afLAqi(jyiwvIc`QErBU>;RU($rS0OBUe#!Q1yQwx!`87@zdmE&kk=_Il+DOTPh9 z7IWc|7t@Ms0IDK+;U`Jo5(5x_4Qa$?5VZq5C3b`e+RWE=I}wG=2-C};Z0TU*H(D|) zjpBS*@V@KSJQq>xa>z5XrUgM=6TUoa=DzbN>@Heq?#yj$XFHZTy}Q+hIll4a7v7k* zXr>+VChD2LyuC^KRg0YZXI_ z@a@zKiR#|?d;k8&#)Y2Rbg+8yi|(pzPJIK;5YrrkFb!tsGfWgQ(Ok}22^>9Q?bPW! zgD@{CJKS8G0ZiCMm^QGjCU@Q)L6U9aBYF`SsaP0dH3$Zx6ubt>?Gajrh}A*GeP1GX@Yj5$A$tQa3}HR z+S8Wm-R1s}{6u8a48t8spn_7gp|0*t(9O9gTpAn?*vIcpcBfRO0F?Wi#!q~HTy2~b z!l+y_BGV&y#8Y&g2zaT8IJQN&&ARb+I@qwEvPqsK)9nus8A2VS<~{b*DB&qT7UZe* zgPy*;z4~vF^eXx)F~5cBtKJg{)(j1N{~kE3Rn)K)L!;VEU_DMgELH z4Vdrg{m$wQDV4K$S39BgxJU97}W7D0nqTSBSa6SJn zqxse?Ti~NT5=y`)MTalmH*P`dBcP{|-NKh2r*xq_8Sv&R(0)e$ms}QDs5}b_mX;(= zi^!3}Sx^}CEL4wrM^+~6@y|Lp?@oVjU6}ZI^UJ$kxQ< zW0%hT(bGnyVWe{x`ymM$5(D+crzI_&NEsTc8XMZ9TQZ0=U!f8Bi3nF(^j`tUY;CJ% zew!BCcy+Wx!+z)xhE`6a%;5#KXk)qpr27tlAM@R4E`ko;!-Rf9%}ry%1fy=z@A?9X ztIeEY$JTuToQe{Q2sYS^g~7FswV#E;zeC0P_1?sWTPRD<98`Httqv%C5@Jx@_UUo7 z2!j@>drg>WVdPYhB6D`lDEpDn3rHjt4vM3 zn-{eg3WDv*S#>6(Ta1au5PJlf$TmeTXGr;=w8zZEU z%p?io5*^oA_d(Wz{f|p(>j0LK(bL_WW2X@lyENXpmulo{UI@7-g4;$K*m&m;m}e)& zG+Vn{*;CL+N)*rE-z<$?w+pav3XQ<)WgAQ{(peBuqU*BIQc$!KDhL+ zj4Ql(a}uTS`|9eIfS=<&q>jKYG^q2L#1k2m66xpW^^@4X=S6UO_#yU+>p7sYJ$m-% zDDGbZKLxRl_1wQiS!SK)xoBMj%x=}Ttx87oCLfp)LAC5TyR z4`VTq8lUSw?CA@Y1|Q=09x+b6q?MI%oZpsrW9s{A51&IN<@t3j0IJ6xV@0-klikOj zv5fV~E<|>jxpyY1|DL?^cVh6lH-YFzz!YXEX}PviQ3;uMrUeI1Px4Y!@7^yR+$t<# zO=nXTx9GbDbydVWa+iBNc@A)ptfp%wpl&_~GQqPsEA3HN)v$qiu%vy&kI+KHNd!n~Gk z_IZ&CjBT_BT0#DfNJD=sNnRN<1{`cNjh|aNhyDf%SQGxGu?j?AKq6e@%); zw8<`>M3pnUw_hD$b=9dO9(p+XPy5=b{a{z`uf-#m0-fSZipVtbXZPDl!rgHS29q?m z@(63RY_|#v{rE=Agg4JTcR1rB z{+{;o?9Cfj=KetF8Uqv`V8gBdhqm_S{`+n>n$iGrRHOb9l2{lP`D6^8=Lq&u zx0u2oV$S-tZ{KZ5Qt`Cm$_~oaJPlV(y(@Dv(M(H9R`Br))7%=*AgDgIu5HAis&B@} zMy}#|WEA9X;>ZSe{+(A?R6sD5ALg6UE6l{kDMyS~y?@?R+2MT6B|jE|mRjVF4R0vqSemChxPl7WE|T zG>kvRujEl0=H^;K3*u{N>tICA7q zLoPO^4heFH#){I{BBxwz{7d-&?iX2cThW?gAhe{zcFL3F7=j5C9VkK-G)roKK9_n04mS|nWG?9v>5fWPZdcp0{dR+O59iIHP=Eo(L zzo#t=y5)4R+3sI|6= zWP6}4l>rneDsng6oc~&HUUsp$Rcb=xyQ=89XVTvxu%f{}J8p0D)O#AnU*<3gWAO3F z$d7RX@B=^$`d~L?oH7L<&fAK-jMG3)KmX|y44k+w&EZ^Cpc2z-3`>G(lkdocS6YuVb zPv>%&Q1@;s$euPgL+-VW5!D|@*zcb>`eNwIFB7{{fRy~CmU8We2DW+bjLhP{`fA%u zHSKS5UTaFrFWP03r!NngAN;az^W7m)?xo=w?T3!68N<|skT+|luQ3RFvuD#suCh?Q z1jDfnrCwp6N_evjqOFrC(-HIpCGae3m;UQn=1{U=DcS~+3UB<7CJKtZ{p{?Eoi-o+ zJ;}l?wo3SXkmkz6bN&i_J=b(`#kkqhSHlTh^Y%71h`$=53`me{omKo?&@|N?uHt6-PpyOwM>w8Tn3}2<*L@)ib=U0HA-|8{BSfMFDOupa2YwmomVjHzj1TL@or9-!afYP zm$?|3KwFPtK4wLV`rAI%vCXm5AB`BPBg4k_4$ zUSTz$*z^2$Vx;ZURj3j~`wmjcHaMUaa6Yr<%W^Lm4p3|Jr#qsSw)nRe;CgIs)hB2u z+yv>NOGa>bk|WrWUSvQc3C3Pu>Sv(6;d=a@>F`yJV>2^kar+)bWgfAo0iXlw12{+L z`v>-7upG}zZ;}g)oMyE6-MP^ZykX((6Z;ycb7qRvo|q@v@GFiVL=24vSZ|XrB|sg9 zaF_6GII3f~Jv42f&IUmIT3+Ul*L#Sa>x1Ov+vHep1DO;=9L|Ig^#u(^T>!mA2g>xk z3L;GgR(s8L-Q@@z^`CKx1$bA*$ocG_M68*qs ziX69|qnmC6`6Tl5Wjw_fwm$vhC`PW9(o9HGSP>pB34Bx`6F)xuG>}l?kdYk%gjyra zDLC>?=Z)Ay)}_n~_|g}Z85bXLXF&Kh(@MQ)>q3LKHNt4)r95~4?Y@~}?c;56L7!W8 zP1AeH5;18(1uWX+%TZ3{ys+44fAS@0>cm5R=3)&Y>rct6tgK9=-n{(exEoQGvtbya zqyy>c>1$=kx%-L3D;$OAaM3`dKd+QoDMSj z=*HcRn<}$aBs>F1tENN#_02UyuWfvz_SKN8i1n$E8N7^;+X|BWM=^@mp(1nm(j6g- zTlQ5~_uyeJh*`4?k-#uy`bhE| z@w9l@JiY30fVW>@l~o+jb@|-~58B-C8P!9#|e2$E$S-;c zSs}9z&o5FASd6p#Fh7nlK^Q3Lzxhsshb_Nx5JwHC9_^D%7gACj8a~6d`+!-;fLREK z6YU(*qXiETObiiejZs9<)O&83q4RdYW>FS^wm$n?JR5cQ^Wza}qk8mqqnv{%zemBm zs*%f`z%nL=Mocp;sJeG(1PY~+B9ufZJvwt#6Am!j$@<`%>3(AzW85~jTy9Eayf zQc*u_k087p?t>8XNM1g@o-_ki>FL{^x40jq|M22Gw8>yV5+IHy5x>D`$Lh1yy*Ra+ z0r7)J>;&qSIF(oF&4~Kv#M=0_;8uQq{#idF7oL$ieUiIuK+z|f3yZ?58t8TD{XxCD zk}fHZMcVl@?D0b{H`WxL1^H&vHq%YZ^`_cM=b_zv*Q4!3`xY2OzE20u-t?3a))~>u z#-5HalC)P&g<}iT;S5AohYwVm*{V^z4r*{~8ynuW{pOZD;ukN^NAC< zp+Rdezp>&P^|Tx@up5$%nLKZF6{~3UwZ>)hvgBA^x$^YW9ro((bh zV*BisBhS#?Fhx%bL`H@;N^n7KtsDv~x(?o&azsu`a}5 z>qgsse!T>VdlGzn?sbb1GOWZY?rBBYzyqS4;^H3Y+CY*U^JGTRC5!tJ0rStG@iI9( zy6Q<2#pL5N<3G5~KW~#MdKfP(@?dFa6KrIL0uohX z)JnNAka$iw(xZ~|9G>JJ@J7;uq!ox|j>k{zKZ5Rq+wL+`O{u8Fkv3mLBziLFM25VQ zJ4JSX-;C5%l>o^*{l>LYbgq(#pMz>TDiWY0vo|=cNWr+nxfJVA*(C$H#m9qfh@9a8 z^y7avtWiF`-?j?=CH4659grcMeco^&6iACc+rlp%r(&MiSm#dd1ZQ{Vbq*gW7+}A{ z@hVCS)DL!4(lkCY=saMtR8C?CUS(z~Vst>K9eTbG!EzL)8vE0DaW9D`fvlUCP|qa$ z9pKXd40pClPNocMN}Arl(Dn3UAZMl-4-07K?9Asf>9R^KBc;>Nf0 zQ{t6YaLaQQHSfzfy3v^P5Kxb4w((sSxtCG03cGK*0C{cu^_(x# zd;Z>j1Zk43H)(Xse!u;ue`Cw&_=a!F9I|4emBRRfbKUd=5cZI}Q88Ee`>~k@{}g8X zW(?V|rbpB%a)$4#$?s#&*)3%Ik)>CW4%0s{gZ+rNX9CZNkhW%RCU2sk5^cu3AH30W zQf`P=H>oIM*|kJkT7{_vAE_e-r>yy1Y0${&6DCaP+o4FM!(J5{xh#9-6sr``Iq_b&BnNO!&`cCqdj^VjjH>zqgc#s+il0X(&gOd<@9BeseY)QiGS+5h(;Lk=Q+_PF{c`8UroHB3A9kQ_4p zH~SBzI&8vM`7y)(R$CuLn?A5|4KtvL?~IS*QU0$-HZ0= zdSQA_tvE5s-E7*r%h0p<6u43$a<$R!qkVn}b}p5$j3hxn7QH6-_OopY@_5Cr3r2#J z^hv&QXBlm}3J8^}5!+I_+E)M5#oY5>NF!y(@6K)BPceDVMl3>%Ok@cb@0> zbAHc#S8kcHh)iy5{R9{Aq;@zI^Vf^Hp?4X5l0Vg}M~^31Y76JO&qP^DL+M)W-g4i4 zca4y^Y0DOK3|3kG-u`f1{K69_#L@m4D6_FFPnRhx!`_lY=rmuoo$zX;)*t!SWc!PM z<7C_|M!U0xM}7V}a5Bc=@phdNSu7S|i(G?VE#80KiQri*NAX-{cY+Rec}>kVX2>~( zrNne3-DqA`s3aT-od;~tz^^!c>T;Vy7BsHtsYFP!Y84Z7*4rvr`n zQR1by@2Ix5c>uJP zl1b2XSNgP?hR9DHbfsk6N({q-gl_jRDJHX>u?e{WOBBcNG%zSh+c=b-L&tJqel1Le z`=vuw3PAPusHh(~1&N91{=(-1zfJl0ahNvRlF!fn#ZSvIFu%B-y6 z6`g_^FZTbuf!-d&WbOlI6rw-5X%7u#Gr3qu_t5Tbo73f!MrVs(azIy6V&?j) z8%ma?Et^79{07Gz3c0{G5v)e`+u|{j-txMq;eceC_TFDXGH!wXV~5xA_=yZ2;7v?4 z36Y(n|0_qvEP|*7c}bs9F-3ZsyZrVXj~kHf4MFsn;iNAl8FA}dlFWShVcY%-lgJjvCR?bjl$;#0$ELqWIdt2bckiW5HJg0%f%bY!yQ}$x=(wS5sMRtN%phNM7(|y>V z->_u8d-vXlzZQ8WESjvJ-YV7BM+tkUa?uQLhF7bu*;Kh_mAUoiJopmkDFjx^ZcLNO zJt>4Nh1miJBpJHo<1*o7#S4wdxVj4tR^5K;=siXPT!~%d`$oZ@wxb`zGGl{OGqom$copVF)c-0%ox~1R!^PhbRFGviVK0F%NIL(+< zp+})gSfRz^r>KA4$=O++pPAaD{c$GaXr0mQqoh(a9+)~94TEv0EU;wZg*Dgwqdkb9_@7wfA-I1z~m058G(xR-@u&1u-( z>Td6R9is=qoI&h-Va~+1y1-A)X^8si78hMft1QZ^E3U#WZfMY2Fo(7{DFs3H5ZxH+(JDAs?5PW$BqaXDoQV-W zMkvJ0so1%O6`0l`N@PPXwaw-Zp(bbmSiW7S3o>7$b4~_cAG}Ce#Tx?RrR^`X=;X{J zk0jInls!Td)im>qi?loTrDcRum}#UO)hkM+(j*pQ_><4RWlo2gKeVY{%vB2j$>P0) z+gsOFnnK4;(IK>LHWZ==)7TvTDkAET*naCr3^kgZH8Ou~T=2E2PaS@`mQj3qdPi7k z%s(;_v0tQ5T6Eo1jE2M{?3_mE8Z|x}MU#8L%_1P`YVs&0nYpHpZ4vVEKWD0PR4sCQ zoGG9)d{-{Fwc64~vc4A`eD_p?*jPtU5fkIQwds(eCHGoiJ}Yce2H_AH9G6S{?E4-c zc>;?_>}JbGTEO;6P-mtI7gdhEBd5BbVsocv2R=}lBZ^T=TzI;HaG7Jl!8fI_1wj8S z$pHnASnv9#==up^%zju}+}8r|hm|kqt+?w=TLuRUb4CFq(DD@Ll9(@`Xx<9MO_8{t zsR1fq!{`(mLC@HZ^O&T1lI==+mQ`Y0f5C19PuWTJ?Q+rlTG1OGXnXV3me+thQ7xCJvnXmg*pfJxvZ^#o0u7e%LGNKdWcEDsAA*f) zw8P`w?V1jKpfJ&*-Dqw7!guOk|6@Zm7Vx&17J1n80pQK!=0hLQ?r>2jOjf>iHwrI>{40+RBs_{rXSeq zM`FX_k1O5+?Y5!)Nd@}qPoB;RFvWj&&Kj9VIIwUXlwVz{OBtmzS1V6eRWx$NhOjLU zsao9=6V)7z-RIC36@VSxm-Mk(;c=aO6$7|IZi6bjB|cpIOH=vw=IJNReQ84}Rq5mS z>tM6csZm&M3ZW-<-M!ltnx>9FT??#YRG2GylQbuE@CWD!<}m0uk5pBNjlF;}Q+Uo; zC)|w7pz3ogu79$zdz@OS%-Xs%7Z(?mkS?dx>ZWYd$OzgQ zocG6e`Vrzf-guq9={|K^Hbp0aT)Y=jndEN_ns^}^?ITlD`L<%*jF|$55dn6toJ%6t zBR}AQ)E<*SZc5E8MvHnxb((1#hZ0Brpv&kspHth|jAzjV_A;E6bg+aK^wS$Zn1%HaUKdPAim_?L9Kq0%IHU0kv5u6M>{Dm>9H)LgGxxe= zt@W;J8=;3~+?9hu;3T}Ds$NGKkfiNNedA5Nt?Ax0L#)>&pu8}yu{M4t%;7LRrF6>V zS0<4aIP%Wi+|4U)V%#>HTM)YSN^5J%A<8cQ8;u5BMH#o_$q1m4ds`e?5YSahO2t*@ zQM-0sqP1pCHWKFqpS8H_G>S0xpi(c>h@xxLc zb(xhtyLazSOImsR`{|1ooxGP-^qi!ROx?5eyu_FOFZ2FwnUdG zM-;zg<9(1&-(DiQxq5mw&iljY5D=RUfAt>hh!z9o3uwF~anpVVZ89x7lvSW{;$^IA zyT?S3*0)}4v%|8=iTzW$GbiRiQgMoj??*ORvaYj3)OtnDUI*)H_r6P2UOC7`>1>H(V8poZ+cMJ1G%K$a@GWu<&P%sj((!O@EPEKP@we$Qlz#j&`cbMnuM5*p-)Yl|8qC-2{F?UEK(6msgk ztWmg;eCx$U=kqkxgJXR<=omW$$8BW~Xw3(Bwxl!fd)1Y1{s% zH37;wiwCcFPI|9_VhXQwyD~gf@p`^UcaWiqEr#es?X+?AeRk@@vK{QZAO_L_&Rt%* z<4}W`XOasMLiJBSCHZ(sLf)NEz9hUwEaTVIy|$-Ez3od5aCR7NA@npSm67&!E250^h>;$T zj{u~5EK6S?NBb;2JG<&kewme?$G6)&yB<{fP_O)z7dzT!`JZ9e$_XUBR!;r8AM?jq z>S6V}Q(J2v{spUbU8t$@QTr=b_kV!pz5&W+{68UZ!@n`6JNLtX`3>8KUQ*xK(7OKJ RrFQ($nyokM;taC`{{n%*@6iAN literal 0 HcmV?d00001 diff --git a/content/docs/v2025.11.21/images/guides/provider/multi-cluster/gke-cluster.png b/content/docs/v2025.11.21/images/guides/provider/multi-cluster/gke-cluster.png new file mode 100644 index 0000000000000000000000000000000000000000..494df9d89d15d117d27d90aeb4540a0e77bd6c8f GIT binary patch literal 35861 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 tZUpjK^g;9n$%EV=I>+q;6Nnyh(%_`;0>A(O literal 0 HcmV?d00001 diff --git a/content/docs/v2025.11.21/images/guides/secret-engines/aws/aws_secret_engine_guide.svg b/content/docs/v2025.11.21/images/guides/secret-engines/aws/aws_secret_engine_guide.svg new file mode 100644 index 000000000..3f161e533 --- /dev/null +++ b/content/docs/v2025.11.21/images/guides/secret-engines/aws/aws_secret_engine_guide.svg @@ -0,0 +1,864 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/guides/secret-engines/azure/azure_secret_engine_guide.svg b/content/docs/v2025.11.21/images/guides/secret-engines/azure/azure_secret_engine_guide.svg new file mode 100644 index 000000000..a5b063b6d --- /dev/null +++ b/content/docs/v2025.11.21/images/guides/secret-engines/azure/azure_secret_engine_guide.svg @@ -0,0 +1,864 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/guides/secret-engines/elasticsearch/elasticsearch_secret_engine_guide.svg b/content/docs/v2025.11.21/images/guides/secret-engines/elasticsearch/elasticsearch_secret_engine_guide.svg new file mode 100644 index 000000000..02226efad --- /dev/null +++ b/content/docs/v2025.11.21/images/guides/secret-engines/elasticsearch/elasticsearch_secret_engine_guide.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/docs/v2025.11.21/images/guides/secret-engines/gcp/gcp_guide.svg b/content/docs/v2025.11.21/images/guides/secret-engines/gcp/gcp_guide.svg new file mode 100644 index 000000000..ba875d2d5 --- /dev/null +++ b/content/docs/v2025.11.21/images/guides/secret-engines/gcp/gcp_guide.svg @@ -0,0 +1,865 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/guides/secret-engines/mariadb/mariadb_secret_engine_guide.svg b/content/docs/v2025.11.21/images/guides/secret-engines/mariadb/mariadb_secret_engine_guide.svg new file mode 100644 index 000000000..246b952bc --- /dev/null +++ b/content/docs/v2025.11.21/images/guides/secret-engines/mariadb/mariadb_secret_engine_guide.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/docs/v2025.11.21/images/guides/secret-engines/mongodb/mongodb_secret_engine_guide.svg b/content/docs/v2025.11.21/images/guides/secret-engines/mongodb/mongodb_secret_engine_guide.svg new file mode 100644 index 000000000..9a3524bd2 --- /dev/null +++ b/content/docs/v2025.11.21/images/guides/secret-engines/mongodb/mongodb_secret_engine_guide.svg @@ -0,0 +1,864 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/guides/secret-engines/mysql/mysql_secret_engine_guide.svg b/content/docs/v2025.11.21/images/guides/secret-engines/mysql/mysql_secret_engine_guide.svg new file mode 100644 index 000000000..ee184cd2f --- /dev/null +++ b/content/docs/v2025.11.21/images/guides/secret-engines/mysql/mysql_secret_engine_guide.svg @@ -0,0 +1,869 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/guides/secret-engines/postgresql/postgres_secret_engine_guide.svg b/content/docs/v2025.11.21/images/guides/secret-engines/postgresql/postgres_secret_engine_guide.svg new file mode 100644 index 000000000..3d2afc039 --- /dev/null +++ b/content/docs/v2025.11.21/images/guides/secret-engines/postgresql/postgres_secret_engine_guide.svg @@ -0,0 +1,864 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/docs/v2025.11.21/images/guides/secret-engines/redis/redis_secret_engine_guide.svg b/content/docs/v2025.11.21/images/guides/secret-engines/redis/redis_secret_engine_guide.svg new file mode 100644 index 000000000..1a2be7921 --- /dev/null +++ b/content/docs/v2025.11.21/images/guides/secret-engines/redis/redis_secret_engine_guide.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/docs/v2025.11.21/images/guides/vault-server/overview_vault_server_guide.svg b/content/docs/v2025.11.21/images/guides/vault-server/overview_vault_server_guide.svg new file mode 100644 index 000000000..95a271981 --- /dev/null +++ b/content/docs/v2025.11.21/images/guides/vault-server/overview_vault_server_guide.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/docs/v2025.11.21/images/guides/vault-server/vault-login.jpg b/content/docs/v2025.11.21/images/guides/vault-server/vault-login.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fa5dd3d86335be14d435efd99e2483e61b1fe92f GIT binary patch literal 22872 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 \ No newline at end of file diff --git a/content/docs/v2025.11.21/images/kubevault-overview.svg b/content/docs/v2025.11.21/images/kubevault-overview.svg new file mode 100644 index 000000000..644722d08 --- /dev/null +++ b/content/docs/v2025.11.21/images/kubevault-overview.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/docs/v2025.11.21/images/monitoring/builtin-prom-vault.jpg b/content/docs/v2025.11.21/images/monitoring/builtin-prom-vault.jpg new file mode 100644 index 0000000000000000000000000000000000000000..32dbd47acb242be0ed0600bda3c4edf786ff008b GIT binary patch literal 33348 zcmeFZ1z225n=ab81q~3K-~>x>w-7vNaMxgI+^vz|4gmte-5Pf%I0U!QxLa_y=Jwvd z?SIb9IWy-zXXeg5yLpOUwYt`-s;|EK^j+)e=hG?xM@~vs3IGQO0Kmci08a}52>>cG zG72&hDhdh;8X7A4GknZv7#Pop@t$Mjlao+Vkdu&+y`*JhcuCDdLq^8P`-Yfy&+fQLgsfJa0?LPA7@wf2Gi4nV|3!lPmr zM}Dqij6&^z&*2}JjY{*js*6B%;)Isd#4!L3o$v(_F$o<#1LG?uE^Z!PK7Ij-cal=l zGO}_X)YLUJwX}6i&CEYqSXx;-IlH*JxqEm9ehvx_2@MO6Pxz9Ul>9X%H77SOzo4+F zxTLzKwywURv8nlccTaC$|G?nTAh$z3!3l825RuFIzk*L^_@x)b7j2)g+bNHj;zm3bT z>O!O8R6QXuahyOWq~%(pJN<2Hzt8O7H?e^Kt(pCOV*i*I1n>+24z_p*xByW=)e`_? z9d!31_X*Hh^91No`4@G~7!@&!?tgLe&qjaJ=}%VqbGQ5{F#eR8f2xiDYc(g5JP^pe z^~3dq{?<%T-4R)7Lq($^xMS0-@(EC$le(xdkD1VYm*&tKjA$RoLX$$~e-K1FYwoNe zZ;@wR0M%DqHe{^A`ChI)h-jJ!z_Nao!RRe$qzYLXZL(6|vg|VA#macNJe0NO%?^@u z@nTKx$(6XrY^q(PVlkyK=DT0G+Y!1`*KjZ6N@t&(g~*yEsk_C~`3w;~b9%VDQ?5hE z$Z0NKuLsI&PtA@Z2B4a`4~VyE+dH*XtWBn0c`>8@GO^<7BK;me%4YI0?%L75OA%SX zC>)2ZDC);Yu}Ec{{Hjidtg%&V`BLq&BNB|y^VEKFn-sY;g;n6a?Qm=?LrF`j_?5#2 z8rM)fC~!n2mGL!+6tBRclwyk9(S!RMp^V=X=FShi4Rbb zwA@V!IQXEj_Fg%V<=aBDxp1LR>4s^KrJ5lINR8)y6mYrT6LaC;XU?w;AHsaw zM`ijvxt3E<=7;05E(NkfG*g-Dl_n2yeM5lkLxI)v5tl?FvxltovMkeRB^@H7FDjA% zd=*V+caz3hR;sTEq(j;M$A>o;S;TVTyR7APr@(A$4O%2p zapVMF0~>6yX)`X<#gOn-#E=L|^Ojlj+d3^W=JS{ckMIZIa-Ln1QJQ8j%OEp5Ik{YU zUE1JHyjTBHPxfkQd?%y5JC%s$Yfdx%6p&;{D=!@Nh^F@ZCSEF;4}~Gh569DG2Tbyr za1y-0TIRsTqb%TI-dz9VlA(&`2~aTtsDn|~1IV=-Nv#%S9zV&Cqc}?Qk@jftL#)G8 zR#}@AcFl?`Wx}R^0FG=cK+4^AqcID;R%3s++0?R7MPQWu?5pqC`7!i(`Oya551lc` z51mOybYuPXb^m#JK6NDpOS5xJdb!Zx6TlVNskc_mYX|-EMw(91eOb6=BH8{K?=v%s zkUib?e)#~%5?g`4j*SB||M`2rSQ!ZZr+&ru$5-dQwm^z?F9%L>Q(I-imu6{B0esp1 zBNLjJy6)LYOKVE34E}UyXELgu{uvIv%31K?jQ_QzOlw)TaJkzJM} zP~N-r^^$?x#Acqpy1v$2oV>~8GeSb+=FVBkv@&w#DbhH#A^pOkF%Jef1#(oVz=2x4X72zQkYF~VPXmJM1teLC%CQiK|_6*4_M3}lJS~n2MK}v3x^}1mLd6>Us0?v;)0zUgW7fdj`iAYdbohU?PevbTi(`w2{-+*uTN8Wa^jg!eBkK1?RW=Lmq-CW8K z9QI%^qT-jthij`{!d1lzoM3*)@nfaWc234wWa(%Pf~SJ;DYHkKqQvOL?q3(sP=56T zzG{5uACOT(N{o=%D(QQ@gx*BaC zrOwq|nVCLEsbO|wb`lMe-_0;F!b>$K9&Y%5W0(3d)JXO`@(DntGVz-zk_2eibu`sr zRW_pDEJla#|J;l14F7G=PV8R^*}v9*owFTNXzUY3&zA%k>RUgm!Eu~qXw%cuB@=a% zd3RGZ6-4Qr5QvzNNp5*hP%Q=$VaA<1lRHfotBAdL0@T|@Bw4AP`J=bW42kWX#YJ;C z^r~fe*nYGsa6IGvpz>ETz~l^inR*~X0G6cU>vE0T3dGF4XWA)O(ef5T&PUd5_;8NG zs%L@@@I&xOOnEs;>cV25%&=M!G+67xjO&`DO(t7adWjkH-xlwRuSR;24CnaKH8rIk znX()=4IpFz;5q?VfTALpH26&-{1+A;(KXyt(MJrOIVeWK6JXu)3Gi9E=LvAZYGZiA z_U#D}R#C~Ag&p$*__N)gborAH{@fpb%7Z`Uv%m)sg$`ZfDwb~%{TFK%9fiQ@nuaP1MrMTQTBUeT&8tRp8HO>z~Ok^RGp=H zdi$?WU{c=kH^dLjDRbb5=h-)-K)W7+tj4xPfIR=ys8%BYr=*Y!i*sMWArq%nc8y$h za_FG@o5>985ds=@Jv;eVh6MjKoW^Xy`O1cOUK%yvy=BU&k*i{dO# zPt`U1eTjW2^wqg7Q%C95<7SAe30KVli<}qbFS;~%mYHtC*7Z%*g4o&zc@u5p%ePdT z{P=|IpI_$R^sbdM>thL#N0;pw0^GuD%d0@3^C;nMitZ}rxpHR1{2!xVQn$9#&dnW=E2o~NtZ z6jfmo{KEKg>@}?~AHrU$Z_K)35JWKwE29P?gJ^7S#dS+G^mDW7)yM~p1pP4G*PIhz z7kSb{(Zj1`6(y_MhHuYpiO4jYI_MgzP-iL87;(i>-G{k9PkYHZ^kDQ}bbHqcVE zdH2=pFpq*h=!^ZBchf@Rd3yrhZr9f*3kz~^QJZ|P<1$b_^ncQjjOhWP?!RERvjcZ; zvwsg$*+6{M7AqHA=V1G`G4fn{<`>0z_et+oHIwZ-?*^5r<}`}ND{wJ(_X_z>kVThp zxZKUzL!K6c1ax$3Y*!LPUwkiD7(N_aIA5M#s5?(vJrpZdRXQ~93NSLe=KdIr%9s-l z`0rk}+W*bnIx}Id11zX0R512=@y&+gFpigCkuxJJP`1D-$x|d9E7KS|!3LF@@0zfa zHX|=#I+ZZ_);H_U`w1X1)QSjkxCvbMaOv~2j0T#QP?8Bz zn9{eMgsho2XFPABrhTK%!Z$eVaA*)zc0<$c`?BR;qcC5RyYG#ersaHlzRcK$#*6Q% z=$7%8gZT^PnGCN{^=w7*F2@kkwiDZ?Td<(#KBJuL`b%v)-@l|nEVm+CDLLNIG~~Nc zkUat7Ol4uAIY!V0oZ5@dc2Wg&1p?=Bu3Nh2Ley6L4$*G5OF!Mf3pVaxR^xhqR|#~~ z2}eczXK)FJ>Y#{`#cx&w^IB&y2!^`urt2@lE`V}o^)@LFKS?yu%Xrxl7@9N@eO|2) zwaS{iWEI4j3b}FI4zqRz1+vI-089k%WHummb%zpN%`1_H;-_p$R89UUiEfTi)d9Yj zC>khaX=ayWo;%Q&6~Pxz08H_uHE>$-cvgn8rz3kmd2aSP z$O9!G3em-TLMt04&-iDxjG8$2`ccNuzHLe7N{~V^}M1(-3vCoIl_EFoL_arE2 zXi+@pt=WgT?Un(!J5F5L(kMZ~R$T7G{(#yP7rgB~aF@vwz&&P-VX>UqH~NdZ>{7j) zh6XIq68rr>LlyrY>w~Fov4%!Bk0pF^u(GDu2zl1lFXm_*DV3=rxd=2i(f~zhcmlkT z{$oXqu&AWnAo~d*%CmBVwep}(@y7~4C#U4rGvwi60kkRzI(7E=!!ewa4s0FPX(eZB zcWveD%jTcuj=$+bI4yyQ26*#k>G|X;OlAi=OiF!>OWxIr7e${ryTrb|t%s%ITw$T4 z-G8p>e8N_pA zfcgSEPRKiMnuY#w45*V-|L5NRxduN&km(Ews>_?Yy&Bod6vr7S!eB$?J5K<~Hl30N(CNA96F`3q8sQ13(`(OP*H=E!6wnCF&3~A+j&eNL3suJm zP{TrFK;WL%Bz6NZgW`5AakrGhdC&yI6z6sv=(AqlX z!YZU?tzk?dlVr?P%_pe!rayZ>bN2uQxP^@2-!|nF{SiOPG$QfSm(#QzEHj`tt;NU>UgbB z=n^_mUz>2Wx9T zFUOIhZl+R&UR5EuEz@ok^p3u&IJksGpsii1mlnj#@D?SBqeXedj*xqHwnYL1$Lchb zwWo4CXzqb6N+dNz8tNS6xwJ^5PX5|D(1;?#VeeU~pAjQM^9|`VY~4vz!T3AJl#1#5 zq%oNK!*)!xNo$$PUS;vVd!YpaE`tvxE)AC}cji{0gNEDPPdYZu`iF5X;dhJgLMzzz zlHUXq!` zg@$$;{(`eDywC&(fJ~q08{kd`-(9TWbhB?q{=UY90@7i-nVN`7qFb>;q6Xk(d3na) zYAs!L%bM-?}|NmjESnB3xQB z4(XSdO^FFQRa@)<9H#t2Scz2AKf)QC3S7~mSO)yv(?1B+lINpB(MCtsuy_l1mT&nkCxK@7H z^FgSyBX+yk?Fl_2PR!$JvW0Q987y=1ZTap((c8l^86J@-m!t`t`WZ|1_IbWYk*M z98FK;5?%PAL%`5-1t4IsH2h;V%h5d==$h4;!JgF3cYs3TQoXxdDTh2>FB< z3BPM=nIA<#O93U3@rnQf^17L}O==tM^$eO$_cV^o9u*_HoNz|K?(tZ}M@kEevEz~nBYUK&QS`S=kcudG_yHoGO`_iO3oubGd!|6%R zO|YGLQvVI=2UErfqW9>cYe3#dKtB{2bVblG!wh=8X?oc#`~={f+^yhx0tD5rTp&>1 z5I+Ha{s!l@>exjVJ>h%;ROap{b|jx+gC~w}Gm<4e3LjWuk>@NTn0Yk@{T_3p3lpkh z>`wsy%*P-~HSj}6tdDIB=*LAf^T;22Ty*!+gf5RCUcROoIB$R+`~Cu&wAl*_GYfoS z`k)!lMzA;S8o{-j6FxBgpY8oJWA_=JFqH}ndmta(Xc{&9O`mx8g!D{z*-7q%mk6) zRbLRWKv?{F>vV(jKrx&I6d#P7(>rtxPeM6+* zfbW9wTDyb_E@_JUln^SwF4Jn8Tf;!R>y?LkzP;wS@U}aj*(ZSTk91A_<~b<2wI;91 z_ZV_W52BdA-;h_r7>}nv=V`0X!uvBG7 zs?4;_CNXifT0IQVMLvqQr$Qh%aSQ5VQv`3FKLPxdN^g?&Cu%K^kH9R61x;$vR866g z#eBBXBmI*F6x6dUtm||G=hVKla`JOfIFZ72uX_c#Iq8Ud{?|XKiE0^XC^kmc;J zK)wx_S=we(Xgy(>3?_`rf$0BOp)2V=s|L9Y@R^R0cZg6=-)gLYGH(gf6@6hol|R&E zw|Ta~#|17)nCWOzeR$AVbOfbfwLkNF^NaQd^@LA@G&xD^x$yl61U8F`u<@EcyB_`&%l71!IwC&?BE-7A7>V}e) zC>9#_Ly0=4ytT`%2O2b#tvIF3`hQAx>Bctoc~JQrNa&tQ_LkRS#Tl_|G+I8)e{7E} zbBOK^94sT3?@lc*#tnPmGzEGaib8mPju_FMGtxV^z%wV`PamKhG6f$Lj<;Q1_MDVhVNi7n?m? zudIt)gHd)q`6(Hm+2qD3+)D@3OtB?f*+>S9cR^hJKr|{0icEW~zwNa36508NnuiNc z7bQF;@~beb0$L7{9Eqyf=k+WI8K{SuLq%50wBaM(3T~`XW%A|@4UZJUQS2<8cKrPO z{UX~rCvG9!HVSI`2X8*#(^b~j-Of~Vc&w&5^o!K$-l*Pfuk;emv4tFE!Azq~#^&nURA|`~K=m-XVcp^$b7?jaNEft*LYN;}S-d-vf!d!h z>9xKv?^3#e`DU+*HMS?-a7goq-BA%Na0T(aX&IcV-LOIW%(I|sQ^8Gpt|IlObQDW; zpd{IVtgZ4CE87b>#G-6rIeovT8ae3xaczqB;wsop z9a%-;xrZW803}v=+lm@!#kD6^M4zTYzKw{9c71jsqtSSkyE#fW+0JFj`Avsj?Ia6# z$}g6VnjNNUrW%hXnj~^RKE4A;A@GGt)5%eJ=Fe2%=WDcTR91C~4gT&%Dg|Dxac;qi z5QuLwX8plHEBN#_oZZi9knhn(@>h9z(!tqu$RWwnuP4Cj3zye8`%3FF7Yc;SGuyZx zQ}WKb)-g)S85?t8W6KwF8j!-s*BSWH`}pV2%#M_YNTcV82}*tP4oE-|AM~bJCNJq5 za7HlR(=dr4@QaEcEEjdc)L*Ommh(%HWI^%Ml7E(N#Zh>pE{@ zUI8VRi9+#KaAGjKE54B;d_=`7&=bU5aC^;%Amo&(GdV5v!HM-Mv(Pf>WZ2CEwQ zMrJ%RawB7AKj7^`*JDXUVgqFZ1-Dgp>Y6L}xl;~SSG8&4- z$y?7CxNvmx{D&e~C#Q?833Xa+r-7s5>K=>;|<7LhLUp}%tD zM;`+*0vRa`;Aohq&m5vf>TvBhfjWnxV-FGWncQ{NHfM9EOjb~~*-LX?LL4g&hLl>Z z+AUj|u_g@t@9dT{DROumY8e?bJD!ChbwJfuRLR{u>?@p`);!nLTx2`0W3BF&<$ zmsJ61`5c2})-hC2YGkyc@@%sWyMwz+rie^VRcJ>AP0Wd-Y{_u>!CQp}O-?SH0jXnF zv5lBs5L0Qc)z15y6k1Fd?&;uxmJ#-0PBM#K;gUK3Wd)Hb-O1V49A~3jOD3!hzEUp| zrszEHXUrpdG1mL%Kx?GLmO_~fhZFZsEhiV?m44ccq_e~9tY1Vk{!A;$vjaqyCS?Xra z_jZ$db?G7@*E0EmRuz}^2yz=JZe@pgRKn2xCkt1nQ7@N^;=r0M1>K~D@?vP23&HwQ z`oj61`7KRHx$e7D*6sYYM;)kTmiDJ*^+@X2LhDTn`es3G`lQKMY%kB~&5+iYNsW&< z1m-Z!b8aH!>t?yWc`=&Tw_1@1*6@)^JTtXZb%+te_WYh^GM%uv?C2Ju3+kkAJk7|* z4&qAJ27)uZS_1Lof(SkDNA;|PW=l+g&67*Q8 zOJex&UWDGdA?_SAzj+~vocFYUcO~&34J2Q0bhmYgl|B&PK}#?BN`c5{R>05xG|_HR zj7 zCp7TfSyzj2;iceLBOH7`WS-NCP`XeGYeXAZ`U`J~gX7 zS7o0U$}zS^&xqsH<0XxH2QdP$Q0Zg_E{b3w`cg^P3|4XKh@DM`XV21u;~d`-v16V#>RJb{v9Us}+QFt*vwn)+NV zTsc<=+F%AYcj+Ob{EI~DK~kTjS6Xo-uP8;Awm4A73=$PwB6z1#1rr>Ef^y<`G_98hDLdw zflXCw+Z)7*lWhE{OdVLzNDup$=wz3j9;A`mG}o>lLhnGchL0qd!;!#Ay`|AK61ma_ z(}J9E=3(JCfA>27=6(Ku^t-4WxZYBqwCu8iU!*ceYla)ZS8SPue#OHB0e*3Hjk~pf zhx%?&k$>#Nm}iwF{sM3*j5aYA=6DDH2F?AgsOr=Aa(|p5#B7Mp(3K$%-nu64I)s!@ zNb)Q!%FY^5(5@1_>f5 zR0p=DhY4Bwn`jgCGJBM;_ft2lLKJGxAL3r8-1q3W)SDjT?%FivloObvogWRP^9_-u zW5a@KpHX@#FVIDAaACM!0_lgBB8)Ki80JEEhIZVPT%$7=9$b3SWbSj_*L1_+t8k~% zkMJ>2M9C*WFRT$NcDU#+KInw{HI%9Cd$>r4W;J%v)X~`g`o4^Jj|KxGxk@cUqEH-4 ze9$IDV z!^r5A{+}KTRC!-=h+c{KVpsZ}KEG(|380OA{{*;ym4)!@1T+SVD;&p3&#yiKGGIZ4 z73#bkKbm_X%JV+a`%RTAchQ|l(DgtuV-_lO4CUc826~I{lYxD^LHT&bB*zFZTGRCe z5P}6f+9fG10-^5xPXO=m_;5hX|37c7X5WP-@iq40@PX#OuT0GzR4RJh0R3zU_)n%7 z`pF;0k@xq`QSNG>_n=*=ygyg#-(+6`ve>s2Ebr1fL>Zxbr37Rh2UM^q_7lLI3-C9_ zX8apLH7LO4`daQaVv{-1&yjO?Zp%84^h1e&{GB`H;-!$j8j2Wvmf7TF#~)BVdx&IP zSf5uc;F?xta&5Nv_+Q%@+c1G7IJsF_*;L=q)|7N79Zjm0Lt(plzZ%f_%*VR!I%+FI zZ5#-8j@VX^-Na+5{1o>#Fc!{ufRFZ!=VAnI+oj|0yG-P-`;mYSACB@L`#0tv{mM!L zr2n>qbN{{}RaL|YHUn@@O=!1nZ>6slWdGJA$M7=t3D5!a?o#9blmY)oh2ne5Tv_8+ zB*n`f2$bKgJ){3Yc|iPcAcEZFM>EmmC%~_Qygv$TG{zFmyY`fP4-iBkDnBzNJ<~GX zbSb)VQOYyiCAhTEI`p`31+vUU#@~=)hVFBs$OylLug*2|DN{2+PP@j3jM^>2#{Tmv z*#^0n1s9xS_^WD}s&{AnRLX>W#H(KD02czJ#7&Z*G)>nZBhN~kFleY~b~|xz!o8Dm zx@lF0xh&7wwPwD;Z$67faq?4I6T|yGGXKBGrT<+_TFXUaUs^m~!2pF(09i?8eLGpN zRoD+l}F_jkZi>qR%5VcM#GE<4(HEa7EnZ>7X&8W2ffWQq0)1sZuA(MJ<0 zo9D#^lsw87|25$M7n2K~Pjn{p8U`E3NZo!|lvM;b&Mc5GTzW#w!ljTawhYA9{uw zUIwdt9S{z76r5?XLq14SxpB2T2HUbZ4~L~sdeAb`#G0D$V36k)*tF$D1ZqNCf_{7O z@~;JV7+Otv{RFuBpsMEh1Sku6d;&avnX!2^d_URRaY!yTIrd|8tX8q=s9(>PMpzP{ zpHre`-RxQvedqHCUeE6S=8+^;xPrJ29{=AqfmHt0F^nUAf!U{j5arx-(y#9ZK(JiR zyaK@ExJP-XH-i8b;@EJfftAOJvS`@KA&Tv-4%FB_Tj;Kj0D|&#m*h(q`X((AbAEk_ zab% zD$YD8Lq68HIFDOenl|&&ZA!F~c?2fRiAH%YSk1Csv(0M!nv)}3iVQpaV(tuI6B?$o|O@7U*G+p{i=8_kpX@oPCvMrUtq(L~xGt)nx!Ao+6v z7Bk#})$7}5$X^$$3D3@J6Ea&ppHD|)dQJ-%WZIqx5fWB$p_&H86MP`aC}||aHdaZ0 zE^A5cx92KFl*iFe+@MgjxmiiHy3_UomZ_OtZ)mYQu<1)13oo>e^8&DL<53GG7@X|rO*Gn`X8BlYY!=(tTWK$(`x zUmITrZpJ)2d;0{ii8FIC7m7OQ_Rk<~b510vt0lCjC9IT2WPDTAvnT}cVV*g5zGs!Aq`wDbJbGq$l<5f(YPbq0g;yM@9aJs|eOEOL(pEI(01b<;q;0e*p9YtD z6fRl2LVSyhN-bx{{m!jL4D_2&j8s3;x-5!Ss3=grk6tEqo&po1(&F`!bY`16Onfl~ z+=pvlr1NZVE-qSK#V_Ksr@(F-9v9F=!*`Yc=u3#yak;#cVog$(oZ1kYy3xbyYJ-)C zG*fH8^mXpX*?A)1e3Xye>7t13vJLd1X=*j&Vt(hHeC3Gmr>@w`*w{i}(PsDZqm?cJ zJ)Nz~i~3n7okeMM$&Xj1)z~aJ=vT)-pJ~i&Cl*>$v-=p^I8twmiV*l@zK?#@ac~L) zy>yCJ3_oNpOJ)x{i3A$6ZjO&Qo>0YWDXNT$oQQ;gEmePii`gy`E6>ppZCM#CB0v@Q zcco_Fb&Ah_Y7z97Ck+fu3@m=ub^YS_Sxol|!LI5bH7?Ej8E=@z6_`99hG|@}YT%fj zEebgjTe1I6YF+PEM+mFxobn`VdHxJ|-HHodjCnc3#$>WPh%pkT+1R<4}BsX9-R zrzS(AUErJNIzd3mEHTG6+Y@Y6;oP|LD;V2*8T){fh-W^u32yAP)YK11_l z72tHNFYOn9bmn8K+%kP!{>(F|w^mt}-Esl}UgX0{-+K&+6Edsp@#{l|1g^K5BAG+ z;vYOf82ANd?}$6i5p4GPE{AhmJ~#NF%B`5$3oSY)ZWbS{GnY9H9+wMIwuR#u|*Q6&M`u zy{HcF??m`UcbUig3dlN*CipmzDn{HMSX?;ffLY7R-BZd#>6S zc5d(s6bZxti6;R3D5K4RdcAy%FbOfSIyu&AZ!|LdT!Q3Ree8egES1jAC#B`1S{KOxG$S>i(Oz|=Lcm+vgV6_4~&*Y71V6BU==d;VA zop!eW%(_gm3bw4&iYpplmjFa0j7*bo$$i1is{j1f3f|sH7kMSKXaYx z#J^xe*a?DludEQegs71@VMiyWztYB3i5#3Z_nhZv&hn8DfHrkArsoj{52^0<8n;mN z=F$rNL+1DLcl&QCpI80-C%)DLJ+M4Jhx)i+-(O`u=u@85TqxaMPKzExK&LJsjnaoa zACu&B^58!X6BauBJ~kn`GY3P0cUZxqwG*(syy!a^EL>j#`dIiIzI~?T3BdS&^vc=b zh>a*_y=lUsB{q|kE+%?01S7L(w8K;-Yz?L(8uh&fv(Z4GoyRwimVc#DQh3jF#J@NL z_|H6H6@9I{F_w_NXew-P-7C$o67hJvYYF#9E-NswCe(4JwmE3=(hBSJ*hFo*802PA z?H7_~QDup1Tr3Zv3Mt|OEd4I6a(|zURn;s`_h;6oRJU9X`VAS!d}wT zAK(1kpXF5zVo}BT>&~%M)Oi-jC(C;EUSd^^=0~*mcfdLz!?vB?}Q1xO)y<@i|{DXnVGZ9!Ghxq}Q~0 zRKB&`W7q2Gwb1g$1>Z{)Q_-Pw25>m6w4-E|cjZLo%j$4(yrj}A8Va04skdjMG5z@7 z4AS-WYpcaDCC&4A>1>8J>k^$;Abrq}!Ks#x%c+NGdC4g9+6d{krf4*-saKNCE{nGY zw*&n`=+jdb;WwVbireebsmxX~st+=}d#BzaN&3l8W>vFwx!Aij8 zOFOVU(+2Tt-%YkU-^Bm{TmCWVK=(`54EWK?lx4&{41P>7~mz8A=nN;`iF9^irK~8ugzSGOCFBx<@^o50txe_mbAd zvC=JY;#~P;2;5$0cW!#AjF$Be97R6rkh;v)dijOza1VZ9@M%~3N_I+ttn=SUY>)vHQH>Rok0G3u zTtz4yRJLV6K_{Re+rVtybY=saA~1wqD2AkPgrqUj!s?|3iqJ;6b)RzoS`1flAcA1C z-C6WXe>t)Upm=Pr^&S6b@Xh#a2140pBHW_rmD7NnEI6x+oHsJ@m;hr z&l%w-XUs5n9b00d5~96=u??*Xs5EL#wfF+jL9u@77Yx3&F*~}9h59%x*Xj$OPy{Z# ze6*z)S-FF@MjI+bTP3{ZFf?dbpo$%X!eZ?r0Gf{B7?l98sh3UDudy;Mwz~FOoC_ zoG0`a6}VDA&0%iKj5UjeN+WK>C{+}f=l=rIo;5%^mt}gqa#4)>_%7Bn>c^=f%h&_) zenoz!q(1GuAj2Mtv2Fpuf=yo^6FM%ppoU?i)l62KItTF>5fRSbN{(`AmA8RpUzXBa zJx};b@5u7xJ**F0$i}Oa!);=O*rZAI&cypAG;^m|sAW|JnayN7W=ndqMCYPGB=L|@ z$dD-8>@pDzgP@66uBiA2rm%t#5+K)L(QlAtChS|6WGKqRh>{BRQP7tQmhMZgH~eir zNw0qm>IFp$?haS&W(5g`!rHtAh;uwW8VW6R@8VAB{x+t9E#uXT2|{#5tV z7n%6vxXQ*po=6L!Gn^%L3NioFEmFl1SJ~o+uNQ5b0m`hSJ_?go)S$@$o@^ zgSuOOf;oJ@XVcAXKxfSRE0>23u;g`}dtXqYbn(8(`(Fp}QfC80_HT>EvZ2y@1`9>H z!bf2s8$zMM^;GV$_w}oy=^pPWFiy?$zT4RFQzd!|xyj`DQk710jk14EaJ9&c{G88M zTOKjCMlOK%mA^faWPO(4i;y~Z*>k`-X!(CVKlm5A}m!%`kt+uBjQBcfidd>!bGxlgidjrMfR0 zrk}LJ%M$`~@3ZPrvU;`JCoV>mv!}TZgeiwyV0w*42^kFgWL!ND-Bs6YK=p}xraBI+zes2KTuLfp0eJVM~v zxh@51-0Jj^^L=7l^rl$+*R6J52ab5D3)kCVnN2dRuLO0#+&xzVw|VCUKB2WR?;-;4 zF6bBgwm&&U8T1|dqM0q09WB(EEM_+2t+^Rj4e!4t2S!0@ICqwktZO&(| z)WCNoHyTvN>X6mo9goXCK*52gQ+@h6xp*Bc+0>%DRUg22L`?8uv-2kwno-XV@%4I3 zSZx%?`qmNs6qqjK-Py9Hzjlg4R9;*>JEV#m8zukpK=hjhdFidS$|s!np^c9aIn?iI z&M!0HzLJ(Vyj!@teca%%D?jq>Ewk>hYgTwWrECmLo`l!nJVK!;SH^%8~+if-KC_4*UQ>y9KoH{rM!dVRr7_q!bWn>_jt ze@{W{DX(Lo0anw0JFwQ=>7;)or2cjbVn||7QYu!q69zDe@nalzHe6^0S?$c_!9gI24ewfg4eYG} zUryi{g2oC9L=q3~RvyCd8Xmp$K)b94>^auBR?UHW@5={_lZ0L(Zp9Yu`zUy7F%~K+ zLNa{W+ucidb-a!Vr16HXb%y$SkX+-H(S-c4Vdrr&iAGqeFrv)O!f7~}2bt14Bn~uC z!ogh$ls3vnwNdCnLtO6&X=tPSDZwnuG?SaD?w+THWfTp zru05Fy;U9fn0j?uw;D%c6vN^mcUBtdebmk5;~Fh#Vz6(ozu=*=SGiCxzMLS}e`Y~* zQSc>mUPdARD#|Z|&e&P1;}zlT`dY_SCQH7Av9zifjd0r@jljj7Ra;2!vsHYJn8O5S zX8umZ*cZZ1W2V}7m`CX*4F#7+fqJ@a&7me50A8mgiu6}l*(T0QqDl+)FQeDCTByV< z1_8jGB9)bMB=I-8Xa!^VclF#W{Dc(}Qb9}>R8tXB5 zkfxSk?MccL&gsMAipWxQLVX+7TGc=5u|xD|Mf*HER^8Bhc2F zA)o80SJXE}3QwBR(zH>hz*bjC*ZVnX&{-tsKHe5qCn*T)82IlHMM{FP%H?FbdV+jQUnnM zqzCj-BZLl0iHd-Lbm?FO1*8{6lon~y#VDajiFA-oM5^?T5PAYB?DhTD_uI$5nYZ(H zc6RqS?~hFG+r2QN>PX zB%P`#9a_$~Su{ZzA<6hY-@`HlnZ{cQF4gfm06i_nZs!;CKpF&m$EVH0ls_}L2Ul?J z@7#AgqGR|T7xX}+@*81>6vo9ksael|&^Q(vjePxvZ~Qx#y4mJIeDo@Y&F;`YBS zMlk|`SIEbUmVcGw^1^jNuRJYt@S<%$j+VvgQitQTIIJ%|#-3K=Sg6P>9Q0p%<(X?$ z40Ecetx1@x6k(KVgD@6UdtZ%J^l-T7tUS@Uzr{V{Q#wQPV{okC;p;ymDO>9<;_=DP z%!A8WPQLpBhR7S>p6_egGQWIHpp)xzg;Dse%XkWFPV2!*i9JSOJO=?_m$J{iZ>iTv z#KO0v>$^V2p<-hrg-gY@8-9*(_$^BQBvdGM{-D8;|7R@y_p=;z{#&DDMDj@Y!B}1r zHKyR_R_~F>AJ+|o*RuU8+AApJAaBEdm4^Ja0ivS~-t*}m zI8{!s8+5OuW6~D3yZoXYVf2j*q=<(>jT!JwL4Tf#1JJp;k^_+SAn!h{Sv=lwgtN=- znnF`suP(XF)_Bi3tuvVs>88lX-_e; z`yXEG=XH3uzI1=~iK_fU<|h0yVZteGC7qOn^BZ#AMF8^8eTrpX+%S-pmBAf|U;t|K zWCGPm1X&RRNI_$tORU~c*__I?Qxj2_S81>#DQIcoV1eY(<^&sd5CkaH}z=b#;E ziKxl1Ec%4Zi(%6w*dyGzwglccvU2Q(236|~ZR`jpb8s1~Sq~%X6z?fcyws!*h2dP)f>6od*WktyNX@klgGk= z?)TrhlICGgYY=*)9w6ok@$P$7ViRWrQhmwPZ3g6C+uT_^>=-%;w^IL&R#&$eO*N~fln>%CX9>>!J4UUjt4Wv5g)$K zS}%!C;5^;T3dy(BS*FX6p_RWLJQxSnyTIyD)^*}LZGbU4%y%X}D3`uXO&;|A;$)DU zh{A*AfRE@`I-Vi(eSvWreSz+|PAMV77P*~9a)Q6Kf$q~K)GL3m689~A1f*kLm;=yi z9y!W!w{W`IFh*oVIkr>ghH>cJ7@!H5SD^e=uXZR7{&7(GmyMRfj;uWaS+J4jI4R#Z zF`gLlO8NzBC|gLNnJb^~{fsO1R_&hba{SamYtywBhLwpJwJ#TeDo-*;9#U4*)JoChH0M^C=3fD}bbv4VS19M7njw?U3r0}fZ%bM51+}g_dqy-?$hg~8~IKW}&4nV|n8Pc0m zai1%PDNZtykdhob2I#nk@b%IdfiSJRk#ku|6>TxTPZa$V(9eul?KYfe%iCGTOQT+l zGL^j#bm?CQw;%!=%Q(0UZ z=3ig-&s3wSQfc`OzwQn6>ISu#K$V-=SR^U z5*JsiTHFUYuuxo4F`RdcZ4IGG3XDSHHCrx?%9NRI<5+`Zt~G2f1gdoADM za5H=5*A-X^k^*Bi0R9ExvbYx8pX=#g!_sc3@^Dygy9;U$Ab~SO5jEACHUiG<5)YoV zRy}5gA;Q|Yz8ZGT9DUjFe&vmRb>z`hH<+crF~9@SfQJ?;Q*YE%TymYD!%5{JgpF`P zjdX^Ay92HJdodocAC7!IP-sTh+dFLXgO;F}E0bWW27wf`d?5~?nAU7$y3(HM_}3(B zb;213I9yrJXGrh>>6f~LsX)w|=ZY_=L$WKUGuf=g9mXkC%I&VZMk`e(D@!TbrFbdG z0ZuFlwjY4(?{Tv|Ci0am)d`l@)|Q>FKki}vIVP<@A4I)Bm}eH2ie(W?&~QP;Z`pq~ z5~vFF`h>-sR7>Es*T#KEZ`7a?Sxp{PRV8r>NOHkHLFX@I)bW_`D&@p14#voIuzwg{ zEEQZ=sV?l9F0ycnxjOG_cZ%cu^U5h2Zhwy>{sZo2Sxb1CdypQ+Yvd-g69MkobGGeV7dYrRP2QpES1 zA>l(B`BkZ;Gh_;X2aJ^Hsr2k2|MHe7uu7wuRJ|+b?p~99A=hOVG94tocGDrd)^N~m zJif4m(9CYj;aa^2r!%ByURt^TM0_emcrC$Zq|RcmxXER&no^O+5w;2jki#|=Py`1E ziB@1}4jv8+@=(4;CV+|FADww;;o(j`@|Z*dWZ!3X42HkH`tX~RXH=-kU5DFR=O}bq z%))ptd-%4q^Pmtm)8@{rW%xG)2s`7PZOd`bvkka~2^sjGz__fw(F8K@!aUDz#y)0{ z7#7DqO7q>GR^jP5l{782nmcK%jSF$WEukfe%sb%P`IyEK=fe`8l~Mu`e;L2L>ZA5{djN$br?qU9^(pWeXZ!rQRMFAZ!(q~ z9vClznTwenLUM4V>#-`&+H)*w1Qi^@affUroBYF8O{p-42UyIkE`9WN<$~EItJ~bF z=cVlusIMxeA(B33C~SAxmqv)$1aLkfxTg&8J^ged=OVJ)!%toa!^JaSawxYsyfQ&% zY})~de(RWbNhg|j^YRWo!zk1()VXU+l&i2iWQ@<^Iy*KU_#enHV@E%@#1N0;mh zslom4hCG)s+0{-jr)%Onyf1PKm^9gR+~xC=Z&Bl*l3O+AY(6b&d9K}KDv>&Z_;UJ_ z_LT(GCD1}FY7x91?CV4hM(^=J$)a(1)fyS#U6~-p2>~sCmK_Xg58&&q*BS>M2Vv_A zrvhPiST`QU+7CS*K98j{03#*L0z(S{74#F@M%ebr15n#0e8YGqGL!8AVrPr_-9S$9h|EkE{&4v6*n@YvR&qbWo1fVk;=VvIY+(c@^=AB73lW+ zI}&sJE)q**nO`ed=Cw&mx7HfFY8*`XM5FJaz$l3ytoS1ot;-usG@>gKGo?%98+)6~ z5ORF&)bh5QXCzSUQX<|JSYS=+;)EVu+8hhYxUt5n+D^e2rZmH|3pyfC75q5%03>4& z)d-BmzJAjK{GskElrymBvWvolR+qXRQD2J|q;w3IkFagfCQGea?T0i3;#tOaUIY1x zBzvS4`=~s${Ou_{C?_EU)tgtk!8U%oJ-3Q?Od_&adc{ex;8vMr7b#avE&fsDYf6y5 zf+t4VbGta5QwLRz{8&?MQDDl!A8`lOvT2#&ckGRVk5GOI6tAvyYg#>{{{~R>Zs)3q zG#Mqd(zoNXz%=;s;f`T*oUB)<8wzwSMVx^Ci43iUdYZY3X^Tp~nPeIS9 z>NlTkvSlv(UZYmVlz6P?lTe9r;N=-FsZ|T)e6)7dz#hI83|4YC>O`T`2TNb>S?xR~ z)I_8V!R?#1&+(qhm59UnVXo<%;l(4sbH>P%TUb7&H1xG$*zo+wJ+Ykhe;_I6xVBoF7vh z4bXsTPhFg#B0SA=50FHdNj(7(REfC_iRP_#Q;~uI2c}lT~Pz}MqD*qe9jl2 zId*)q*gFXO#j-`qu(}96FrH` z@758~1C38zsA%XiL#OTiCMzaZu$nShLNhL0ykrerndh#8$QpyV9?9`R>J*(*Zn`UF z%YMs6RjY&Y)KTw9_#^b}gP$pWAem;vs4mH{D{h{5MfyOHK1uI2#+2o zhdmPbgBB{v!)N9EoXhstzEj{|8_9qt^y(`7a}#9#f#BC@6Xoik~{(aytnndfJPBx|SGIUJ2JIJw_nc~<#jml$;-s%Hm zACqO2|L6Bx-AdA+F8G3|3`pDW-vb2nJ%E_BjvoJITc7&381yXsR zJyfnO#le6v5&yfdj@c!hX6+;uql8V~>;8nlpYZ=N-_By&Vn|Wv({p3ve!7Dz$p34B P{AWGx|Is)7!SKHU%Jh^r literal 0 HcmV?d00001 diff --git a/content/docs/v2025.11.21/images/monitoring/coreos-prom-vault.png b/content/docs/v2025.11.21/images/monitoring/coreos-prom-vault.png new file mode 100644 index 0000000000000000000000000000000000000000..3ae6001462e02462be7554ba10cfa61eae0c4d9a GIT binary patch literal 32966 zcmdSAWmKF^*CvX)gy0?^!JXii0D<5H2=4Cg?(XgqJh;0A*Cx0$?$)?BG>0d7pKoT) zn)x;7`*CXBt9#wmrF+-jwd<;@!xiKt&{2p`prD}8CBKR(LP5bMLqS1@A|bryyrXlm zc>RKN6p>U$dQDzPMq#h-gic@7oRn-$oLu!CjG;_zY^{x%91R_ejcpvwY@N zLP?5!R(8ueS#{S^-rX9yn5;pg%?o=+|C)Z#rM2gknVm{AGij{ijoCzkwCf)mwKc1l zxXU%0wAzbQEX*xzT6Ys#S!j_WP>=%Ny^Cb;>v@8tL4TXFgPVHn(q*yj8|U432M~sU zz4p~(Hh02tEaQvbK)J>)hy6`jQlBAZ(?fD|YM5AmQY(N?IpXhceOjXsJ6edH^PH&I zpHzh%eYC*j?Il;*u^q!-?`Nb>l`Tt_kLTQUzfXMpcfzgzA88w zXWMrUD{csIZK^Ku-^+D$sRg)_dXB1wazB0A5z8SV4RCZ;-I*Nb4ARW;@>_!tdA;-P zIg-8alxM99RCQkXXR46*^o=FcgZ<%)-eN`gsqQx1Kvxp|SwT^=b%vzMbt{VU4()9J zAEVV%$>$cop==#~wi7L&?}t3Q>v<7WO`$$aP9iegfUZ$G{5^QV;gfYLTi+Nmv2`YF z3r(Aek*@CsW{Qxcb+|@CU2A+mI*Jo>+TG=oOXa+);Olqqf8*P_sxrd68@(sj8(T*2 zH&*u>^R~5o^ScUp@3}VX%5;yVr*-!$8L?V_049E-!YzC`3-_ukjqL5jR;D%K+;_oO z6+T4%3{Y^#YOOty?n>YDk1pG92(B<-;ak0V=RIEj;9(1kaAz6mI*K9$p+Mn~bK^Xd z%RPSs{ z=lPJ($a2w?1QKmL=8`p2TD??A)k($oX2+I+ik~VzZGFC$7lQL;b|XZS+(aP{`*)mX zt~Gji_xZ28+9EJNIK=L1VzU9IR1{sBtjxZ<)@v!pk*F<|8Mfx}t3-9 zyL>M5988@B?of541ej-;CdRw@tqWPTUR$ZO_R03;nDU^TIKAurPNU7qr;G!?jFPzeZ;ru-Oi5u z88CF_sUIN)5J4fh9w1%$*l@_7hGnRgezhx=5Xo}Y>1-{Qx~AVhI2f;E-mUwOHEflZ z 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 H*7f}_O;0y< literal 0 HcmV?d00001 diff --git a/content/docs/v2025.11.21/images/monitoring/csi-vault-prom-builtin.png b/content/docs/v2025.11.21/images/monitoring/csi-vault-prom-builtin.png new file mode 100644 index 0000000000000000000000000000000000000000..d968053ce04af97043b4c97576254d00cbe12f6f GIT binary patch literal 81199 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