Deploys a Vault cluster on Kubernetes running on GCP in an opinionated fashion.
This module makes use of the official Vault Helm Chart.
You should be familiar with various concepts for Vault first before continuing
You will need to have the following resources available:
- A Kubernetes cluster, managed by GKE, or not
- Helm with Tiller running on the Cluster or you can opt to run Tiller locally
- If you are planning to use the Raft storage for Vault, you will need to have the Google Compute Engine Persistent Disk CSI Driver installed on your cluster. GKE users can enable this in their cluster.
You will need to have the following configured on your machine:
- Credentials for GCP
- Credentials for Kubernetes configured for
kubectl
If you are using GKE and have configured kuebctl
with credentials using
gcloud container clusters get-credentials [CLUSTER_NAME]
only, your account in Kubernetes might
not have the necessary rights to deploy this Helm chart. You can
give
yourself the necessary rights by running
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole cluster-admin --user [USER_ACCOUNT]
where [USER_ACCOUNT]
is your email address.
This module uses the Helm Chart for Vault to deploy Vault running on a Kubernetes Cluster.
In addition, for (opinionated) operational reasons, this module additionally provisions the following additional resources:
Either
- A Google Cloud Storage (GCS) Bucket for storing Vault State and to provide High Availability
- GCE disks for storage of raft state
and
- A Google KMS keyring with keys for auto unsealing Vault and encrypting storage
- (Optional) A separate GKE Node pool purely for running Vault
This module makes use of both the google-beta
provider. See the documentation on
GCP provider versions.
It might be useful to refer to Hashicorp's guide on how to harden your Vault cluster.
The sections below would detail additional considerations that are specific to the setup that this module provides.
The most granular permissions that you can assign to most GCP resources is at the project level. Therefore, you should provision the resources for Vault, wherever possible, in their own separate GCP project. You could use Google's Project Factory module to Terraform a new project specifically for Vault.
HA is enabled "for free" by our use of the GCS bucket for storage. Optionally, you can choose to use
a Consul) cluster, running on the Kubernetes Cluster or not for
HashiCorp HA only. If you choose to do so, remember to set storage_ha_enabled
to "false"
.
You need to generate a set of self-signed certificates for Vault to communicate. Refer to the CA Guide for more information.
Remember to encrypt the private key before checking it into your repository. You can use the
google_kms_secret
data
source to decrypt during apply time.
You must provide the unencrypted PEM encoded certificate and key in the variables tls_cert_pem
and tls_cert_key
respectively.
You should run Vault in a separate namespace and provision all the Kubernetes resources in this namespace. Then, you can make use of RBAC to control access to resources in this namespace.
You should also consider running Vault on a separate nodes from the rest of your workload. You should also make use of taints and tolerations to make sure that these nodes run Vault exclusively.
In addition, you should configure various
Admission Controllers
to control access to pod tolerations using
PodTolerationRestriction
and nodes from modifying their own taints using
NodeRestriction
.
The basic configuration provided in this module configures the following:
listener
stanzaseal
stanza for auto-unsealing via GCP KMS.storage
stanza using the GCS bucket or Raft storage.service_registration
stanza for Kubernetes.
Not all required parameters are automatically configured. For example, the
api_addr
field is not automatically
configured.
You should refer to Vault's documentation on
the additional options available and provide them in the vault_config
variable.
The first time you deploy Vault, you need to initialise Vault. You can do this by kubectl exec
into one of the pods.
Assuming you have deployed the Helm chart using the release name vault
in the default
namespace,
you can find the list of pods using
kubectl get pods --namespace default --selector=release=vault
Choose one of the pods and exec
into the pod:
kubectl exec --namespace default -it vault-xxxx-xxxx -c vault sh
# Once inside the pod, we can run
vault operator init -tls-skip-verify
Make sure you take note of the recovery keys and the intial root token!
If you lose the recovery key, you will lose all your data.
You should then exec
into the remaining pods and force a restart of the container
kill -15 1
You will only need to do this for the first time.
Vault is set up to auto unseal using the KMS key provisioned by this module. You will generally not have to worry about manually unsealing Vault if the nodes have access to the keys.
Name | Version |
---|---|
terraform | >= 0.15 |
google-beta | >= 4.0 |
helm | >= 2.0 |
kubernetes | >= 2.0 |
Name | Version |
---|---|
google-beta | >= 4.0 |
helm | >= 2.0 |
kubernetes | >= 2.0 |
local | n/a |
null | n/a |
No modules.
Name | Description | Type | Default | Required |
---|---|---|---|---|
agent_default_cpu_limit | Default CPU Limit for injected agent containers | string |
"500m" |
no |
agent_default_cpu_request | Default CPU request for injected agent containers | string |
"250m" |
no |
agent_default_memory_limit | Default memory Limit for injected agent containers | string |
"128Mi" |
no |
agent_default_memory_request | Default memory request for injected agent containers | string |
"128Mi" |
no |
agent_default_template_type | Default template type for secrets when no custom template is specified. Possible values include: "json" and "map". | string |
"map" |
no |
agent_image_repository | Image repository for the Vault agent that is injected | string |
"hashicorp/vault" |
no |
agent_image_tag | Image tag for the Vault agent that is injected | string |
"1.9.0" |
no |
api_addr | Set the api_addr configuration for Vault HA. See https://www.vaultproject.io/docs/configuration#api_addr If set to null, this will be set to the Pod IP Address | any |
null |
no |
auth_path | Mount path of the Kubernetes Auth Engine that the injector will use | string |
"auth/kubernetes" |
no |
chart_name | Helm chart name to provision | string |
"vault" |
no |
chart_repository | Helm repository for the chart | string |
"https://helm.releases.hashicorp.com" |
no |
chart_version | Version of Chart to install. Set to empty to install the latest version | string |
"0.18.0" |
no |
enable_auth_delegator | uthDelegator enables a cluster role binding to be attached to the service account. This cluster role binding can be used to setup Kubernetes auth method. https://www.vaultproject.io/docs/auth/kubernetes.html | bool |
true |
no |
exit_on_retry_failure | Exit agent on templating failure | bool |
true |
no |
external_traffic_policy | External traffic policy for Vault. Only applicable for LoadBlaancer/NodePort | string |
"Cluster" |
no |
external_vault_addr | External vault server address for the injector to use. Setting this will disable deployment of a vault server along with the injector. | string |
"" |
no |
fullname_override | Helm resources full name override | string |
"" |
no |
gcs_extra_parameters | Additional paramaters for GCS storage in HCL. See https://www.vaultproject.io/docs/configuration/storage/google-cloud-storage | string |
"" |
no |
gcs_storage_enable | Enable the use of GCS Storage | any |
n/a | yes |
gcs_storage_use | Use GCS storage in Vault configuration. Setting this to false allows GCS storage resouces to be created but not used with Vault | bool |
true |
no |
gke_boot_disk_kms_key | KMS Key to encrypt the boot disk. Set to null to not use any |
string |
null |
no |
gke_cluster | Cluster to create node pool for | string |
"<REQUIRED if gke_pool_create is true>" |
no |
gke_disk_type | Disk type for the nodes | string |
"pd-standard" |
no |
gke_enable_integrity_monitoring | Enable integrity monitoring of nodes | bool |
false |
no |
gke_enable_secure_boot | Enable secure boot for GKE nodes | bool |
false |
no |
gke_image_type | Type of image for GKE nodes | string |
"COS_CONTAINERD" |
no |
gke_labels | Labels for the GKE nodes | map |
{} |
no |
gke_machine_type | Machine type for the GKE nodes. Make sure this matches the resources you are requesting | string |
"n1-standard-2" |
no |
gke_metadata | Metadata for the GKE nodes | map |
{} |
no |
gke_node_count | Initial Node count. If regional, remember to divide the desired node count by the number of zones | number |
3 |
no |
gke_node_size_gb | Disk size for the nodes in GB | string |
"20" |
no |
gke_node_upgrade_settings | Surge upgrade settings as per https://cloud.google.com/kubernetes-engine/docs/concepts/cluster-upgrades#surge | object({ max_surge = number, max_unavailable = number }) |
{ |
no |
gke_node_upgrade_settings_enabled | Enable/disable gke node pool surge upgrade settings | bool |
false |
no |
gke_pool_create | Whether to create the GKE node pool or not | bool |
false |
no |
gke_pool_location | Location for the node pool | string |
"<REQUIRED if gke_pool_create is true>" |
no |
gke_pool_name | Name of the GKE Pool name to create | string |
"vault" |
no |
gke_tags | Network tags for the GKE nodes | list |
[] |
no |
gke_taints | List of map of taints for GKE nodes. It is highly recommended you do set this alongside the pods toleration. See https://www.terraform.io/docs/providers/google/r/container_cluster.html#key for the keys and the README for more information | list |
[] |
no |
global_enabled | Globally enable or disable chart resources | bool |
true |
no |
ingress_annotations | Annotations for server ingress | map |
{} |
no |
ingress_class_name | Ingress Class name for the server | string |
"" |
no |
ingress_enabled | Enable ingress for the server | bool |
false |
no |
ingress_hosts | Hosts for server ingress | list |
[ |
no |
ingress_labels | Labels for server ingress | map |
{} |
no |
ingress_tls | Configuration for server ingress | list |
[] |
no |
injector_affinity | YAML string for injector pod affinity | string |
"podAntiAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n - labelSelector:\n matchLabels:\n app.kubernetes.io/name: {{ template \"vault.name\" . }}-agent-injector\n app.kubernetes.io/instance: \"{{ .Release.Name }}\"\n component: webhook\n topologyKey: kubernetes.io/hostname\n" |
no |
injector_enabled | Enable Vault Injector | bool |
true |
no |
injector_env | Extra environment variable for the injector pods | map |
{} |
no |
injector_failure_policy | Configures failurePolicy of the webhook. Default behaviour depends on the admission webhook version. See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#failure-policy | string |
"Ignore" |
no |
injector_image_repository | Image repository for Vault Injector | string |
"hashicorp/vault-k8s" |
no |
injector_image_tag | Image tag for Vault Injector | string |
"0.14.1" |
no |
injector_leader_elector_enabled | Enable leader elector for Injector if > 1 replicas | bool |
true |
no |
injector_log_format | Log format for the injector. standard or json | string |
"standard" |
no |
injector_log_level | Log level for the injector. Supported log levels: trace, debug, error, warn, info | string |
"info" |
no |
injector_metrics_enabled | enable a node exporter metrics endpoint at /metrics | bool |
false |
no |
injector_priority_class_name | Priority class name for injector pods | string |
"" |
no |
injector_replicas | Number of injector replicas | number |
1 |
no |
injector_resources | Resources for the injector | map |
{ |
no |
injector_tolerations | YAML string for injector tolerations | string |
"" |
no |
key_ring_name | Name of the Keyring to create. | string |
"vault" |
no |
kms_location | Location of the KMS key ring. Must be in the same location as your storage bucket | any |
n/a | yes |
kms_project | Project ID to create the keyring in | any |
n/a | yes |
kubernetes_annotations | Annotations for Kubernetes in general | map |
{} |
no |
kubernetes_labels | Labels for Kubernetes in general | map |
{ |
no |
kubernetes_namespace | Namespace for Kubernetes resources | string |
"default" |
no |
labels | Labels for GCP resources | map |
{ |
no |
max_history | Max history for Helm | number |
20 |
no |
namespace_selector | The selector for restricting the webhook to only specific namespaces. See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-namespaceselector for more details. | map |
{} |
no |
node_port | If type is set to 'NodePort', a specific nodePort value can be configured, will be random if left blank. | string |
"30000" |
no |
object_selector | objectSelector is the selector for restricting the webhook to only specific labels. See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-objectselector | map |
{} |
no |
project_id | Project ID for GCP Resources | any |
n/a | yes |
psp_annotations | Template YAML string for PSP annotations | string |
"seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default,runtime/default\napparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default\nseccomp.security.alpha.kubernetes.io/defaultProfileName: runtime/default\napparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default\n" |
no |
psp_enabled | Enable PSP | bool |
false |
no |
raft_backup_max_retention_days | Maximum daily age of the snapshot that is allowed to be kept. | number |
14 |
no |
raft_backup_policy | Data disk backup policy name | string |
"vault-data-backup" |
no |
raft_disk_labels | Override labels for Raft GCE PD resources. Will use var.labels if set to null |
map(string) |
null |
no |
raft_disk_regional | Use regional disks instead of zonal disks | bool |
true |
no |
raft_disk_size | Size of Raft disks in GB | number |
10 |
no |
raft_disk_snapshot_labels | Override labels for Raft GCE PD snapshot resources. Will use var.labels if set to null |
map(string) |
null |
no |
raft_disk_type | Raft data disk type | string |
"pd-ssd" |
no |
raft_disk_zones | List of zones for disks. If not set, will default to the zones in var.region | list(string) |
[] |
no |
raft_extra_parameters | Extra parameters for Raft storage in HCL | string |
"" |
no |
raft_persistent_disks_prefix | Prefix of the name persistent disks for Vault to create. The prefix will be appended with the index | string |
"vault-data-" |
no |
raft_region | GCP Region for Raft Disk resources | string |
"" |
no |
raft_replica_zones | List of replica zones for disks. If not set, will default to the zones in var.region | list(list(string)) |
[ |
no |
raft_set_node_id | Set Raft Node ID as the name of the vault pod | bool |
true |
no |
raft_snapshot_daily | Take snapshot of raft disks daily | bool |
true |
no |
raft_snapshot_day_of_weeks | Map where the key is the day of the week to take snapshot and the value is the time of the day | map |
{ |
no |
raft_snapshot_days_in_cycle | Number of days between snapshots for daily snapshots | number |
1 |
no |
raft_snapshot_enable | Create data disk resource backup policy | bool |
true |
no |
raft_snapshot_hourly | Take snapshot of raft disks hourly | bool |
false |
no |
raft_snapshot_hours_in_cycle | Number of hours between snapshots for hourly snapshots | number |
1 |
no |
raft_snapshot_start_time | Time in UTC format to start snapshot. Context depends on whether it's daily or hourly | string |
"19:00" |
no |
raft_snapshot_weekly | Take snapshot of raft disks weekly | bool |
false |
no |
raft_storage_enable | Enable the use of Raft Storage | any |
n/a | yes |
raft_storage_use | Use Raft storage in Vault configuration. Setting this to false allows Raft storage resouces to be created but not used with Vault | bool |
true |
no |
release_name | Helm release name for Vault | string |
"vault" |
no |
revoke_on_shutdown | Attempt to revoke Vault Token on injected agent shutdown. | bool |
true |
no |
server_affinity | Server affinity YAML string | string |
"podAntiAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n - labelSelector:\n matchLabels:\n app.kubernetes.io/name: {{ template \"vault.name\" . }}\n app.kubernetes.io/instance: \"{{ .Release.Name }}\"\n component: server\n topologyKey: kubernetes.io/hostname\n" |
no |
server_annotations | Annotations for server | map |
{} |
no |
server_config | Additional configuration for the server in HCL that will be appended to the module's configuration | string |
"" |
no |
server_enabled | Enable Vault Server | bool |
true |
no |
server_env | Server extra environment variables | map |
{} |
no |
server_extra_args | Extra args for the server | string |
"" |
no |
server_extra_containers | List of extra server containers | any |
[] |
no |
server_image_repository | Server image repository | string |
"hashicorp/vault" |
no |
server_image_tag | Server image tag | string |
"1.9.0" |
no |
server_labels | Labels for server | map |
{} |
no |
server_liveness_probe_enable | Enable server liness probe | bool |
true |
no |
server_liveness_probe_path | Server liveness probe path | string |
"/v1/sys/health?standbyok=true" |
no |
server_log_format | Configure the logging format for the Vault server. Supported log formats include: standard, json | string |
"" |
no |
server_log_level | Configure the logging verbosity for the Vault server. Supported log levels include: trace, debug, info, warn, error | string |
"" |
no |
server_priority_class_name | Priority class name for server pods | string |
"" |
no |
server_readiness_probe_enable | Enable server readiness probe | bool |
true |
no |
server_readiness_probe_path | Path for server readiness probe | string |
"" |
no |
server_replicas | Number of replicas. Should be either 3 or 5 for raft | number |
5 |
no |
server_resources | Resources for server pods | map |
{ |
no |
server_secret_env | Extra secret environment variables for server | list |
[] |
no |
server_share_pid | Share PID for server pods | bool |
false |
no |
server_tolerations | YAML string for server tolerations | string |
"" |
no |
server_update_strategy | Configure the Update Strategy Type for the StatefulSet. See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies | string |
"RollingUpdate" |
no |
server_volume_mounts | Extra volume mounts for server | list |
[] |
no |
server_volumes | Extra volumes for server | list |
[] |
no |
service_account_annotations | Annotations for service account | map |
{} |
no |
service_account_create | Create service account for server | bool |
true |
no |
service_account_name | Override name for service account | string |
"" |
no |
service_annotations | Annotations for the service | map |
{} |
no |
service_type | Service type for Vault | string |
"ClusterIP" |
no |
static_secret_render_interval | Static secret render interval for the agent | string |
"" |
no |
storage_bucket_class | Storage class of the bucket. See https://cloud.google.com/storage/docs/storage-classes | string |
"REGIONAL" |
no |
storage_bucket_labels | Set of labels for the storage bucket | map |
{ |
no |
storage_bucket_location | Location of the storage bucket. Defaults to the provider's region if empty. This must be in the same location as your KMS key. | string |
"" |
no |
storage_bucket_name | Name of the Storage Bucket to store Vault's state | string |
"" |
no |
storage_bucket_project | Project ID to create the storage bucket under | string |
"" |
no |
storage_ha_enabled | Use the GCS bucket to provide HA for Vault. Set to false if you are using alternative HA storage like Consul | bool |
true |
no |
storage_key_name | Name of the Vault storage key | string |
"storage" |
no |
storage_key_rotation_period | Rotation period of the Vault storage key. Defaults to 90 days | string |
"7776000s" |
no |
sts_annotations | Annotations for server StatefulSet | map |
{} |
no |
timeout | Time in seconds to wait for any individual kubernetes operation. | number |
600 |
no |
tls_cert_ca | PEM encoded CA for Vault | any |
n/a | yes |
tls_cert_key | PEM encoded private key for Vault | any |
n/a | yes |
tls_cert_pem | PEM encoded certificate for Vault | any |
n/a | yes |
tls_cipher_suites | Specifies the list of supported ciphersuites as a comma-separated-list. Make sure this matches the type of key of the TLS certificate you are using. See https://golang.org/src/crypto/tls/cipher_suites.go | string |
"" |
no |
ui_active_vault_pod_only | Only select active vault server pod for UI service | bool |
true |
no |
ui_annotations | Annotations for UI service | map |
{} |
no |
ui_external_traffic_policy | External traffic policy for UI. Only applicable for LoadBlaancer/NodePort | string |
"Cluster" |
no |
ui_load_balancer_ip | UI Load balancer IP | string |
"" |
no |
ui_load_balancer_source_ranges | Load balancer source ranges for UI service | list |
[] |
no |
ui_publish_unready | Publish unready pod IP address for UI service | bool |
false |
no |
ui_service_enable | Enable an additional UI service | bool |
false |
no |
ui_service_node_port | Service node port for UI | string |
"" |
no |
ui_service_port | Port for UI service | number |
8200 |
no |
ui_service_type | Service Type for UI | string |
"ClusterIP" |
no |
unauthenticated_metrics_access | If set to true, allows unauthenticated access to the /v1/sys/metrics endpoint. | bool |
false |
no |
unseal_key_name | Name of the Vault unseal key | string |
"unseal" |
no |
unseal_key_rotation_period | Rotation period of the Vault unseal key. Defaults to 6 months | string |
"7776000s" |
no |
values_file | Write Helm chart values to file | string |
"" |
no |
vault_node_service_account | Service Account for Vault Node Pools if Workload Identity is enabled | string |
"vault-gke-node" |
no |
vault_server_location_description | Location of Vault server to put in description strings of resources | string |
"" |
no |
vault_server_service_account | Service Account name for the Vault Server | string |
"vault-server" |
no |
vault_service_account | Required if you did not create a node pool. This should be the service account that is used by the nodes to run Vault workload. They will be given additional permissions to use the keys for auto unseal and to write to the storage bucket | string |
"<REQUIRED if not creating GKE node pool>" |
no |
workload_identity_enable | Enable Workload Identity on the GKE Node Pool. For more information, see https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity | bool |
false |
no |
workload_identity_project | Project to Create the Service Accoutn for Vault Pods if Workload Identity is enabled. Defaults to the GKE project. | string |
"" |
no |
Name | Description |
---|---|
key_ring_self_link | Self-link of the KMS Keyring created for Vault |
node_pool_service_account | Email ID of the GKE node pool service account if created |
release_name | Release name of the Helm chart |
storage_key_self_link | Self-link of the KMS Key for storage |
unseal_key_self_link | Self-link of the KMS Key for unseal |
vault_server_service_account | Email ID of the Vault server Service Account if created |