mirror of https://github.com/crossplane/docs.git
docs snapshot for crossplane version `master`
This commit is contained in:
parent
9d79e92f04
commit
4ab539ce60
|
|
@ -0,0 +1,324 @@
|
|||
---
|
||||
title: Vault Credential Injection
|
||||
toc: true
|
||||
weight: 230
|
||||
indent: true
|
||||
---
|
||||
|
||||
# Using Vault for Provider Credentials
|
||||
|
||||
> This guide is adapted from the [Vault on Minikube] and [Vault Kubernetes
|
||||
> Sidecar] guides.
|
||||
|
||||
Most Crossplane providers support supplying credentials from at least the
|
||||
following sources:
|
||||
- Kubernetes Secret
|
||||
- Environment Variable
|
||||
- Filesystem
|
||||
|
||||
A provider may optionally support additional credentials sources, but the common
|
||||
sources cover a wide variety of use cases. One specific use case that is popular
|
||||
among organizations that use [Vault] for secrets management is using a sidecar
|
||||
to inject credentials into the filesystem. This guide will demonstrate how to
|
||||
use the [Vault Kubernetes Sidecar] to provide credentials for [provider-gcp].
|
||||
|
||||
> Note: in this guide we will copy GCP credentials into Vault's KV secrets
|
||||
> engine. This is a simple generic approach to managing secrets with Vault, but
|
||||
> is not as robust as using Vault's dedicated cloud provider secrets engines for
|
||||
> [AWS], [Azure], and [GCP].
|
||||
|
||||
## Setup
|
||||
|
||||
> Note: this guide walks through setting up Vault running in the same cluster as
|
||||
> Crossplane. You may also choose to use an existing Vault instance that runs
|
||||
> outside the cluster but has Kubernetes authentication enabled.
|
||||
|
||||
Before getting started, you must ensure that you have installed Crossplane and
|
||||
Vault and that they are running in your cluster.
|
||||
|
||||
1. Install Crossplane
|
||||
|
||||
```console
|
||||
kubectl create namespace crossplane-system
|
||||
|
||||
helm repo add crossplane-stable https://charts.crossplane.io/stable
|
||||
helm repo update
|
||||
|
||||
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
|
||||
```
|
||||
|
||||
2. Install Vault Helm Chart
|
||||
|
||||
```console
|
||||
helm repo add hashicorp https://helm.releases.hashicorp.com
|
||||
helm install vault hashicorp/vault
|
||||
```
|
||||
|
||||
3. Unseal Vault Instance
|
||||
|
||||
In order for Vault to access encrypted data from physical storage, it must be
|
||||
[unsealed].
|
||||
|
||||
```console
|
||||
kubectl exec vault-0 -- vault operator init -key-shares=1 -key-threshold=1 -format=json > cluster-keys.json
|
||||
VAULT_UNSEAL_KEY=$(cat cluster-keys.json | jq -r ".unseal_keys_b64[]")
|
||||
kubectl exec vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY
|
||||
```
|
||||
|
||||
4. Enable Kubernetes Authentication Method
|
||||
|
||||
In order for Vault to be able to authenticate requests based on Kubernetes
|
||||
service accounts, the [Kubernetes authentication backend] must be enabled. This
|
||||
requires logging in to Vault and configuring it with a service account token,
|
||||
API server address, and certificate. Because we are running Vault in Kubernetes,
|
||||
these values are already available via the container filesystem and environment
|
||||
variables.
|
||||
|
||||
```console
|
||||
cat cluster-keys.json | jq -r ".root_token" # get root token
|
||||
|
||||
kubectl exec -it vault-0 -- /bin/sh
|
||||
vault login # use root token from above
|
||||
vault auth enable kubernetes
|
||||
|
||||
vault write auth/kubernetes/config \
|
||||
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
|
||||
kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
|
||||
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
|
||||
```
|
||||
|
||||
5. Exit Vault Container
|
||||
|
||||
The next steps will be executed in your local environment.
|
||||
|
||||
```console
|
||||
exit
|
||||
```
|
||||
|
||||
## Create GCP Service Account
|
||||
|
||||
In order to provision infrastructure on GCP, you will need to create a service
|
||||
account with appropriate permissions. In this guide we will only provision a
|
||||
CloudSQL instance, so the service account will be bound to the `cloudsql.admin`
|
||||
role. The following steps will setup a GCP service account, give it the
|
||||
necessary permissions for Crossplane to be able to manage CloudSQL instances,
|
||||
and emit the service account credentials in a JSON file.
|
||||
|
||||
```console
|
||||
# replace this with your own gcp project id and the name of the service account
|
||||
# that will be created.
|
||||
PROJECT_ID=my-project
|
||||
NEW_SA_NAME=test-service-account-name
|
||||
|
||||
# create service account
|
||||
SA="${NEW_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
|
||||
gcloud iam service-accounts create $NEW_SA_NAME --project $PROJECT_ID
|
||||
|
||||
# enable cloud API
|
||||
SERVICE="sqladmin.googleapis.com"
|
||||
gcloud services enable $SERVICE --project $PROJECT_ID
|
||||
|
||||
# grant access to cloud API
|
||||
ROLE="roles/cloudsql.admin"
|
||||
gcloud projects add-iam-policy-binding --role="$ROLE" $PROJECT_ID --member "serviceAccount:$SA"
|
||||
|
||||
# create service account keyfile
|
||||
gcloud iam service-accounts keys create creds.json --project $PROJECT_ID --iam-account $SA
|
||||
```
|
||||
|
||||
You should now have valid service account credentials in `creds.json`.
|
||||
|
||||
## Store Credentials in Vault
|
||||
|
||||
After setting up Vault, you will need to store your credentials in the [kv
|
||||
secrets engine].
|
||||
|
||||
> Note: the steps below involve copying credentials into the container
|
||||
> filesystem before storing them in Vault. You may also choose to use Vault's
|
||||
> HTTP API or UI by port-forwarding the container to your local environment
|
||||
> (`kubectl port-forward vault-0 8200:8200`).
|
||||
|
||||
1. Copy Credentials File into Vault Container
|
||||
|
||||
Copy your credentials into the container filesystem so that your can store them
|
||||
in Vault.
|
||||
|
||||
```console
|
||||
kubectl cp creds.json vault-0:/tmp/creds.json
|
||||
```
|
||||
|
||||
2. Enable KV Secrets Engine
|
||||
|
||||
Secrets engines must be enabled before they can be used. Enable the `kv-v2`
|
||||
secrets engine a the `secret` path.
|
||||
|
||||
```console
|
||||
kubectl exec -it vault-0 -- /bin/sh
|
||||
|
||||
vault secrets enable -path=secret kv-v2
|
||||
```
|
||||
|
||||
3. Store GCP Credentials in KV Engine
|
||||
|
||||
The path of your GCP credentials is how the secret will be referenced when
|
||||
injecting it into the `provider-gcp` controller `Pod`.
|
||||
|
||||
```console
|
||||
vault kv put secret/provider-creds/gcp-default @tmp/creds.json
|
||||
```
|
||||
|
||||
4. Clean Up Credentials File
|
||||
|
||||
You no longer need our GCP credentials file in the container filesystem, so go
|
||||
ahead and clean it up.
|
||||
|
||||
```console
|
||||
rm tmp/creds.json
|
||||
```
|
||||
|
||||
## Create a Vault Policy for Reading Provider Credentials
|
||||
|
||||
In order for our controllers to have the Vault sidecar inject the credentials
|
||||
into their filesystem, you must associate the `Pod` with a [policy]. This policy
|
||||
will allow for reading and listing all secrets on the `provider-creds` path in
|
||||
the `kv-v2` secrets engine.
|
||||
|
||||
```console
|
||||
vault policy write provider-creds - <<EOF
|
||||
path "secret/data/provider-creds/*" {
|
||||
capabilities = ["read", "list"]
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
## Create a Role for Crossplane Provider Pods
|
||||
|
||||
1. Create Role
|
||||
|
||||
The last step is to create a role that is bound to the policy you created and
|
||||
associate it with a group of Kubernetes service accounts. This role can be
|
||||
assumed by any (`*`) service account in the `crossplane-system` namespace.
|
||||
|
||||
```console
|
||||
vault write auth/kubernetes/role/crossplane-providers \
|
||||
bound_service_account_names="*" \
|
||||
bound_service_account_namespaces=crossplane-system \
|
||||
policies=provider-creds \
|
||||
ttl=24h
|
||||
```
|
||||
|
||||
2. Exit Vault Container
|
||||
|
||||
The next steps will be executed in your local environment.
|
||||
|
||||
```console
|
||||
exit
|
||||
```
|
||||
|
||||
## Install provider-gcp
|
||||
|
||||
You are now ready to install `provider-gcp`. Crossplane provides a
|
||||
`ControllerConfig` type that allows you to customize the deployment of a
|
||||
provider's controller `Pod`. A `ControllerConfig` can be created and referenced
|
||||
by any number of `Provider` objects that wish to use its configuration. In the
|
||||
example below, the `Pod` annotations indicate to the Vault mutating webhook that
|
||||
we want for the secret stored at `secret/provider-creds/gcp-default` to be
|
||||
injected into the container filesystem by assuming role `crossplane-providers`.
|
||||
There is also so template formatting added to make sure the secret data is
|
||||
presented in a form that `provider-gcp` is expecting.
|
||||
|
||||
```console
|
||||
echo "apiVersion: pkg.crossplane.io/v1alpha1
|
||||
kind: ControllerConfig
|
||||
metadata:
|
||||
name: vault-config
|
||||
spec:
|
||||
metadata:
|
||||
annotations:
|
||||
vault.hashicorp.com/agent-inject: \"true\"
|
||||
vault.hashicorp.com/role: "crossplane-providers"
|
||||
vault.hashicorp.com/agent-inject-secret-creds.txt: "secret/provider-creds/gcp-default"
|
||||
vault.hashicorp.com/agent-inject-template-creds.txt: |
|
||||
{{- with secret \"secret/provider-creds/gcp-default\" -}}
|
||||
{{ .Data.data | toJSON }}
|
||||
{{- end -}}
|
||||
---
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-gcp
|
||||
spec:
|
||||
package: crossplane/provider-gcp:v0.16.0
|
||||
controllerConfigRef:
|
||||
name: vault-config" | kubectl apply -f -
|
||||
```
|
||||
|
||||
## Configure provider-gcp
|
||||
|
||||
One `provider-gcp` is installed and running, you will want to create a
|
||||
`ProviderConfig` that specifies the credentials in the filesystem that should be
|
||||
used to provision managed resources that reference this `ProviderConfig`.
|
||||
Because the name of this `ProviderConfig` is `default` it will be used by any
|
||||
managed resources that do not explicitly reference a `ProviderConfig`.
|
||||
|
||||
> Note: make sure that the `PROJECT_ID` environment variable that was defined
|
||||
> earlier is still set correctly.
|
||||
|
||||
```console
|
||||
echo "apiVersion: gcp.crossplane.io/v1beta1
|
||||
kind: ProviderConfig
|
||||
metadata:
|
||||
name: default
|
||||
spec:
|
||||
projectID: ${PROJECT_ID}
|
||||
credentials:
|
||||
source: Filesystem
|
||||
fs:
|
||||
path: /vault/secrets/creds.txt" | kubectl apply -f -
|
||||
```
|
||||
|
||||
## Provision Infrastructure
|
||||
|
||||
The final step is to actually provision a `CloudSQLInstance`. Creating the
|
||||
object below will result in the creation of a Cloud SQL Postgres database on
|
||||
GCP.
|
||||
|
||||
```console
|
||||
echo "apiVersion: database.gcp.crossplane.io/v1beta1
|
||||
kind: CloudSQLInstance
|
||||
metadata:
|
||||
name: postgres-vault-demo
|
||||
spec:
|
||||
forProvider:
|
||||
databaseVersion: POSTGRES_9_6
|
||||
region: us-central1
|
||||
settings:
|
||||
tier: db-custom-1-3840
|
||||
dataDiskType: PD_SSD
|
||||
dataDiskSizeGb: 10
|
||||
writeConnectionSecretToRef:
|
||||
namespace: crossplane-system
|
||||
name: cloudsqlpostgresql-conn" | kubectl apply -f -
|
||||
```
|
||||
|
||||
You can monitor the progress of the database provisioning with the following
|
||||
command:
|
||||
|
||||
```console
|
||||
kubectl get cloudsqlinstance -w
|
||||
```
|
||||
|
||||
<!-- named links -->
|
||||
|
||||
[Vault on Minikube]: https://learn.hashicorp.com/tutorials/vault/kubernetes-minikube
|
||||
[Vault Kubernetes Sidecar]: https://learn.hashicorp.com/tutorials/vault/kubernetes-sidecar
|
||||
[Vault]: https://www.vaultproject.io/
|
||||
[Vault Kubernetes Sidecar]: https://www.vaultproject.io/docs/platform/k8s/injector
|
||||
[provider-gcp]: https://github.com/crossplane/provider-gcp
|
||||
[AWS]: https://www.vaultproject.io/docs/secrets/aws
|
||||
[Azure]: https://www.vaultproject.io/docs/secrets/azure
|
||||
[GCP]: https://www.vaultproject.io/docs/secrets/gcp
|
||||
[unsealed]: https://www.vaultproject.io/docs/concepts/seal
|
||||
[Kubernetes authentication backend]: https://www.vaultproject.io/docs/auth/kubernetes
|
||||
[kv secrets engine]: https://www.vaultproject.io/docs/secrets/kv/kv-v2
|
||||
[policy]: https://www.vaultproject.io/docs/concepts/policies
|
||||
Loading…
Reference in New Issue