This tutorial will walk you through deploying a set of microservices that utilize short-lived TLS certificates for secure communication between microservice and their clients.
Be sure to complete the Deployment Guide tutorial first.
This tutorial will require remote access to the Vault server running in your cluster. Set up a proxy from your local machine to the Vault server:
kubectl -n vault-controller port-forward \
$(kubectl -n vault-controller \
get pods -l app=vault \
-o jsonpath='{.items[0].metadata.name}') \
8200:8200
Forwarding from 127.0.0.1:8200 -> 8200
Forwarding from [::1]:8200 -> 8200
At this point you can now use the vault cli in a separate terminal to interact with the remote Vault server.
export VAULT_ADDR="http://127.0.0.1:8200"
export VAULT_TOKEN="3e4a5ba1-kube-422b-d1db-844979cab098"
Verify the status of the remote Vault server:
vault status
Output:
Sealed: false
Key Shares: 1
Key Threshold: 1
Unseal Progress: 0
Version: 0.6.2
Cluster Name: vault-cluster-963019e9
Cluster ID: 5e36a011-cc89-0dcb-a261-ae8c3c31dfd4
High-Availability Enabled: false
Each Pod will generate a dynamic set of short-lived TLS certificates, using its unique Vault token, from the Vault PKI secret backend. In this sections you'll complete the following tasks:
- Enable the Vault PKI secret backend
- Configure a CA certificate
- Create a Vault policy that enables clients to generate TLS certificates
- Create PKI roles to limit usage of TLS certificates
Mount the PKI secret backend:
vault mount pki
Generate a root certificate:
vault mount-tune -max-lease-ttl=87600h pki
vault write pki/root/generate/internal common_name=cluster.local ttl=87600h
vault write pki/config/urls issuing_certificates="http://vault:8200/v1/pki/ca"
vault write pki/config/urls issuing_certificates="http://vault:8200/v1/pki/ca" \
crl_distribution_points="http://vault:8200/v1/pki/crl"
In this section you'll setup two PKI roles which allow us to define a policy used when generating TLS certificates.
Create the client PKI role:
vault write pki/roles/client \
allowed_domains="cluster.local" \
allow_subdomains="true" \
client_flag="true" \
max_ttl="72h" \
server_flag="false"
Create the server PKI role:
vault write pki/roles/server \
allow_any_name="true" \
allowed_domains="cluster.local" \
allow_subdomains="true" \
client_flag="false" \
max_ttl="72h" \
enforce_hostnames="false" \
server_flag="true"
The allow_any_name
and enforce_hostnames
flags are being set here to enable the ability to generate server certificates that contain Kubernetes service names in the DNS Subject Alternative Names field of the issued certificate. This means clients can lookup the service using a DNS short name such as foo
, which maps to foo.default.svc.cluster.local
, and still be able to validate the server side certificate.
In this section we need to create a Vault policy that will enable Pods to generate certificates. Pods generate secrets by writing to a PKI issue path based on the role (/pki/issue/<role name>
).
vault policy-write microservice policies/microservice.hcl
At this point tokens with the microservice
policy can generate TLS certs from the following paths:
pki/issue/client
pki/issue/server
The vaultproject.io/policies
Pod annonation can be used to generate tokens with a set of policies. To include the microservice policy add the following annotation to a Pod spec:
vaultproject.io/policies: "default,microservice"
The default policy is required because it enables you to renew tokens and other house keeping tasks.
The server
Pod will utilize the vault-init
container to obtain a dedicated Vault token from the Vault Controller. Once the server
container starts it will fetch a short-lived TLS certificate from the Vault PKI secret backend and start serving traffic on port 443.
The TLS server certificate will be validate for the following IPs and DNS names:
- The service name as configured with the
--service-name
flag - IP SANs: POD IP address and 127.0.0.1
- service-name.namespace.svc.cluster.local
- pod-ip.namespace.pod.cluster.local
- hostname.subdoamin.namespace.svc.cluster.local
See the Using DNS Pod and Services guide for more information.
Create the server
ReplicaSet:
kubectl -n vault-controller create -f replicasets/server.yaml
Expose the server
Pods internally:
kubectl -n vault-controller create -f services/server.yaml
View the logs for the server
Pod:
kubectl -n vault-controller logs \
$(kubectl -n vault-controller \
get pods -l app=server \
-o jsonpath='{.items[0].metadata.name}')
Log Output:
2016/10/31 04:07:44 Reading vault secret file from /var/run/secrets/vaultproject.io/secret.json
2016/10/31 04:07:44 Successfully renewed the client token; next renewal in 43200 seconds
2016/10/31 04:07:45 renewing cert in 29 seconds
At this point the other Pods can access the server
service using the https://server
address, but each client will require a signed client certificate from the PKI secret backend.
In this section you'll deploy a client Pod that will talk to the server
service. The client Pods will also utilize the vault-init
container to get a unique Vault token that will be used to generate a set of short-lived client certificates.
Create the client
ReplicaSet:
kubectl -n vault-controller create -f replicasets/client.yaml
Once the client
container starts it will obtain a short-lived client certificate from the PKI path pki/issue/client
. For demonstration purposes each TLS certificate is generated with a TTL of 60 seconds and automatically renewed by the client
and server Pods before they expire. The certificate TTL can be adjusted using the -client-pki-ttl
flag.
View the logs for the client
Pod:
kubectl -n vault-controller logs \
$(kubectl -n vault-controller \
get pods -l app=client \
-o jsonpath='{.items[0].metadata.name}')
Log Output:
2016/10/31 04:24:44 Reading vault secret file from /var/run/secrets/vaultproject.io/secret.json
2016/10/31 04:24:44 Successfully renewed the client token; next renewal in 43200 seconds
2016/10/31 04:24:45 renewing cert in 29.726472304
2016/10/31 04:24:50 Hello from server service
2016/10/31 04:24:55 Hello from server service
At this point the client
Pod contacts the server
service every 5 minutes, and continuously renew it Vault token and client certificate in the background.
The kelseyhightower/microservice
container can be used in both client and server mode by setting the appropriate flags. At this point you can test different configurations, service names, and deployments of the kelseyhightower/microservice
container to get a fell for working with vault and short-lived TLS certificates.
microservice -h
Usage of microservice:
-addr string
HTTPS service address (default "0.0.0.0:443")
-client-pki-path string
PKI secret backend issue path (e.g., '/pki/issue/<role name>')
-client-pki-ttl string
certificate time to live (default "60s")
-cluster-domain string
Kubernetes cluster domain (default "cluster.local")
-hostname string
hostname as defined by pod.spec.hostname
-ip string
IP address as defined by pod.status.podIP
-name string
name as defined by pod.metadata.name
-namespace string
namespace as defined by pod.metadata.namespace (default "default")
-remote-addr string
remote server address (e.g., 'service-name:443')
-server-pki-path string
PKI secret backend issue path (e.g., '/pki/issue/<role name>')
-server-pki-ttl string
server certificate time to live (default "60s")
-service-name string
Kubernetes service name that resolves to this Pod
-subdomain string
subdomain as defined by pod.spec.subdomain
-vault-addr string
Vault service address (default "https://vault:8200")