The objective of this example is to demonstrate how we can use SPIRE in a Kubernetes environment to provide identities to different microservices and use mTLS between them.
This demo has 4 namespaces spire
, postgres-ns
, api-ns
and client-ns
server is configured with k8s_psat
node attestor to validate identity of agents and agent has k8s
workload attestor to validate identity of microservices using workload API and SDS.
Customer-db contains a postgresql database with ssl mode, that uses SVIDs provided to authenticate postgres users that are trying to connect to database, and a postgres-sidecar (spiffe-helper) that attest against Workload API and store SVIDs on disk and rotates certificates calling reload.sh.
api this pod contains a REST API that attest using Workload API and present SVIDs to postgres to authenticate symuser
(SVID has a DNS with postgres user to authenticate), and an Envoy, configured to use SDS endpoint and uses it in mTLS redirecting to API.
The last part is the client pod, that contains a CMD client for REST API, and an Envoy that is configured with SDS endpoint and mTLS agains api proxy.
Diagram
- spire
- spire-server-0: SPIRE Server statefulSet
- spire-agent-xxxx: agents daemonseat
- postgres-ns
- customer-db-0: customer database pod
- postgres: postgresql database, configured for SSL authentication
- postgres-sidecar: spiffe-helper that attest against SPIRE Agent and stores SVID on disk
- customer-db-0: customer database pod
- api-ns
- api-xxxx-xxx: api pod
- api: REST API that attest against SPIRe Agent and presents SVID to postgres
- api-proxy: Envoy container configured to get SVIDs using SPIRE Agent SDS in a mTLS listener
- api-xxxx-xxx: api pod
- client-ns
- client-xxxx-xxxx: client pod
- client: simple REST API client
- client-proxy: Envoy container configured to get SVIDs using SPIRE Agent SDS, and connect to api-proxy with mTLS
- client-xxxx-xxxx: client pod
All entries are created using entries.json
Entry used to put an alias to our Agent, in this example we are using k8_psat node attestor
spifeID: spiffe://example.org/spire-agent-node
node SPIFFE IDparentID: spiffe://example.org/spire/server
allnodes
must have Server as parentselector: k8s_psat:agent_ns:spire
agent must be in namespacespire
selector: k8s_psat:agent_sa:spire-agent
agent must use service accountspire-agent
selector: k8s_psat:cluster:spire-cluster
: agent must be in clusterspire-cluster
parentID: spiffe://example.org/spire-agent-node
: agent SPIFFE IDspiffeID: spiffe://example.org/postgres-sidecar
: SVID SPIFFE IDselector: k8s:container-name:postgres-sidecar
: workload must be in containerpostgres-sidecar
selector: k8s:ns:postgres-ns
: workload must be in namespacepostgres-ns
ttl 60
: SVIDs expires in 60 seconds
parentID spiffe://example.org/spire-agent-node
: node SPIFFE IDspiffeID spiffe://example.org/api
: SVID SPIFFE IDselector k8s:container-name:api
: workload must be in containerapi
selector k8s:ns:api-ns
: workload must be in namespaceapi-ns
dns symuser
: SVID used to validate users on Postgres must contains the user name they want to authenticate as a DNSttl 60
: SVIDs expires in 60 seconds
parentID spiffe://example.org/spire-agent-node
: node SPIFFE IDspiffeID spiffe://example.org/api-proxy
: SVID SPIFFE IDselector k8s:container-name:api-proxy
: workload must be in containerapi-proxy
selector k8s:ns:api-ns
: workload must be in namespaceapi-ns
ttl 60
: SVIDs expires in 60 seconds
parentID spiffe://example.org/spire-agent-node
: node SPIFFE IDspiffeID spiffe://example.org/client-proxy
: SPIFFE ID del SVIDselector k8s:container-name:client-proxy
: workload must be in containerclient-proxy
selector k8s:ns:client-ns
: workload must be in namespaceclient-ns
ttl 60
: SVIDs expires in 60 seconds
For this example we uses kind
with a cluster that allows the use of psat
1-cluster-create.sh
: download all dependencies and creates a cluster (using kind). In casekind
orkubectl
this script download them on folder./bin
, creates a link to them if exists.2-build-images.sh
: build required images (spiffe-helper, api y client).3-deploy.sh
: add images to kind and creates namespaces with all required entries.4-call-client.sh
: call CLI to get customers from postgres.5-make-db-fails.sh
: updates DNS for postgres SVID to an invalid user. To validate connection is broken execute4-call-client.sh
, getting status500
.6-make-envoy-mtls-fails.sh
: update selector on api-proxy entry, to prevent api-proxy to get new SVIDs, after ~1m call4-call-client.sh
to get status503
.7-restore-entries.sh
: restore entries to initial state. After some seconds execute4-call-client.sh
to verify cient is able to connect postgres again.8-cluster-delete.sh
: delete cluster.