This guide will walk you through how to migrate an existing Kubernetes Workload Registrar deployment to SPIRE Controller Manager. Existing entries created by the Kubernetes Workload Registrar aren't compatible with SPIRE Controller Manager so they'll be deleted and replaced with new entries. Workloads will continue to function with their existing SVIDs. After switching over they'll get pushed new SVIDs based on the new entries.
Note As we'll be deleting and creating entries, it's important to do this migration during a downtime window.
First clean up the Kubernetes Workload Registrar and its resources.
- Delete the
ValidatingWebhookConfiguration,Service,Roles, and other k8s-workload-registrar config. Not all of the resources below are applicable for all Kubernetes Workload Registrar modes, so if there's a "not found" message it's safe to ignore. In general make sure to clean up any Kubernetes Workload Registrar resources aside from the SPIRE Server and Kubernetes Workload Registrar itself. Those will be removed below.kubectl delete validatingwebhookconfigurations k8s-workload-registrar k8s-workload-registrar-webhook kubectl delete service k8s-workload-registrar -n spire kubectl delete clusterrolebindings k8s-workload-registrar-role-binding spire-k8s-registrar-cluster-role-binding kubectl delete clusterroles k8s-workload-registrar-role spire-k8s-registrar-cluster-role kubectl delete rolebinding spire-k8s-registrar-role-binding -n spire kubectl delete role spire-k8s-registrar-role -n spire kubectl delete configmaps k8s-workload-registrar k8s-workload-registrar-certs -n spire kubectl delete secret k8s-workload-registrar-secret
Next deploy the new SPIRE Controller Manager.
-
Create the
ClusterSPIFFEIDCustom Resource Definition (CRD),ValidatingWebhookConfiguration,Service,Roles, and other SPIRE Controller Manager config.kubectl apply -f ../config/crd/bases/spire.spiffe.io_clusterspiffeids.yaml \ -f ../config/crd/bases/spire.spiffe.io_clusterfederatedtrustdomains.yaml \ -f ../config/crd/bases/spire.spiffe.io_clusterstaticentries.yaml \ -f config/spire-controller-manager-webhook.yaml \ -f config/leader_election_role.yaml \ -f config/leader_election_role_binding.yaml \ -f config/role.yaml \ -f config/role_binding.yaml \ -f config/spire-controller-manager-config.yaml \ -f config/spire-server.yaml -
Create the
ClusterSpiffeIdcustom resource. The below example will create SPIFFE IDs with this shape:spiffe://<trust domain>/ns/<namespace>/sa/<serviceaccount>. Only Pods with the labelspiffe.io/spiffe-id: truewill have entries auto-created. This corresponds to theidentity_templateandidentity_template_labelconfigurables from CRD mode Kubernetes Workload Registrar.kubectl apply -f config/clusterspiffeid.yaml
Note See FAQs for instructions on how to translate label, annotation, and service account based workload registration. Also see ClusterSPIFFEID definition for more information on how to create the most suitable shape for your environment.
The CRD mode requires an additional step of removing the SpiffeId CRD. SPIRE Controller Manager uses a different CRD, so this one needs to be removed and resources cleaned up.
-
Manually remove the finalizers with the below script. SPIRE Controller Manager will automatically clean up entries, so the finalizers can safely be removed.
for ns in $(kubectl get ns | awk '{print $1}' | tail -n +2) do if [ $(kubectl get spiffeids -n $ns 2>/dev/null | wc -l) -ne 0 ] then kubectl patch spiffeid $(kubectl get spiffeids -n $ns | awk '{print $1}' | tail -n +2) --type='merge' -p '{"metadata":{"finalizers":null}}' -n $ns fi done
-
Delete the SpiffeId CRD. This will delete all entries created by the k8s-workload-registrar. If you have a lot of SpiffeId resources this may take a little while to complete.
kubectl delete crd spiffeids.spiffeid.spiffe.io
Finally verify SPIRE Controller Manager deployed correctly.
-
Verify the Pods came up correctly. The
spire-server-0Pod should have two containers running in it.$ kubectl get pods -n spire NAME READY STATUS RESTARTS AGE spire-agent-5jkzg 1/1 Running 0 46m spire-server-0 2/2 Running 1 (11m ago) 11m
Note It's ok to see a restart in the
spire-server-0Pod. SPIRE Controller Manager relies on the SPIRE Server to get a certificate for it's Webhook, and when SPIRE Controller Manager comes up first it can't get that certificate and restarts. See #39. -
Deploy this example NGINX Deployment.
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/application/simple_deployment.yaml
-
Add the 'spiffe.io/spiffe-id' label to the Deployment Template. This will reroll the Deployment.
kubectl patch deployment nginx-deployment -p '{"spec":{"template":{"metadata":{"labels":{"spiffe.io/spiffe-id": "true"}}}}}' -
From the SPIRE Server you should see a single entry with SPIFFE ID
spiffe://example.org/ns/default/sa/default.$ kubectl exec spire-server-0 -n spire -c spire-server -- ./bin/spire-server entry show Found 1 entry Entry ID : c93a53bd-c313-4239-a13b-75ebf292db8f SPIFFE ID : spiffe://example.org/ns/default/sa/default Parent ID : spiffe://example.org/spire/agent/k8s_psat/demo-cluster/85ad58a6-64ae-4cc7-a126-f60dfa5b8139 Revision : 0 X509-SVID TTL : default JWT-SVID TTL : default Selector : k8s:pod-uid:dca56e85-142e-4de2-b04a-257ac8d7e3c8
-
When done you can delete the NGINX deployment, this will automatically delete the SPIFFE ID.
kubectl delete -f https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/application/simple_deployment.yaml
With this configuration Kubernetes Workload Registrar took a specified Label off of a Pod and used that to form the SPIFFE ID. For example:
pod_label = "spiffe.io/spiffe-id"
This can be done with the SPIRE Controller Manager with a config like the below:
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
name: label-based
spec:
spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/{{ index .PodMeta.Labels \"spiffe.io/spiffe-id\" }}"
podSelector:
matchExpressions:
- key: "spiffe.io/spiffe-id"
operator: "Exists"The matchExpressions statement will select only Pods with the spiffe.io/spiffe-id label. For Pods with this label, the spiffeIDTemplate will extract the value of this label and use it to form the SPIFFE ID.
Note Allowing the value of labels to directly populate a SPIFFE ID gives the power to create arbitrary SPIFFE IDs to anyone that can deploy a Pod in your cluster. It's better to define a SPIFFE ID using a template that doesn't depend on a label. See ClusterSPIFFEID defintion for more information.
There is no equivalent to this configuration in SPIRE Controller Manager. Annotations specifically don't allow for selecting Pods with a specific annotation, which SPIRE Controller Manager relies on. The easiest path forward is to convert the annotations to labels and use label based workload registration.
This can be done with the SPIRE Controller Manager with a config like the below:
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
name: service-account-based
spec:
spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"Note This will create an entry for every Pod in the system. For use cases where every Pod needs a certificate this configuration will work well. If you prefer to limit what Pods get a certificate, restrict it with a label like in the main example in
config/clusterspiffeid.yaml. Also see ClusterSPIFFEID defintion for more information.
With Kubernetes Workload Registrar the Pod annotation spiffe.io/federatesWith is used to create SPIFFE ID's that federate with other trust domains. For example:
apiVersion: v1
kind: Pod
metadata:
annotations:
spiffe.io/federatesWith: example.io,example.ai
name: test
...The equivalent with SPIRE Controller Manager is accomplished with the federatesWith field of the ClusterSPIFFEID CRD.
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
name: federation
spec:
spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
podSelector:
matchLabels:
spiffe.io/spiffe-id: "true"
federatesWith: ["example.io", "example.ai"]
You can add multiple DNS names with the dnsNameTemplates field of the ClusterSPIFFEID CRD.
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
name: federation
spec:
spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
podSelector:
matchLabels:
spiffe.io/spiffe-id: "true"
dnsNameTemplates: ["{{ .PodMeta.Name }}", "my-custom-dns-name"]
Yes, this is enabled with the sample configuration in this migration guide.
For each ClusterSPIFFEID you want to auto populate DNS names for, set the autoPopulateDNSNames field there. See example.
Note Spire Controller Manager 0.4.0 or later is required to auto populate DNS names.
This is not supported with SPIRE Controller Manager, they must be in the same Pod. If you require them to be in separate Pods, please open a new issue with your use case.
Yes, but it requires the use of a separate CRD (ClusterStaticEntry).
$ kubectl logs spire-server-0 -n spire -c spire-controller-manager
2022-12-13T00:41:21.362Z INFO setup Config loaded {"cluster name": "demo-cluster", "trust domain": "example.org", "ignore namespaces": ["kube-system", "kube-public", "istio-system", "spire", "local-path-storage"], "gc interval": "10s", "spire server socket path": "/spire-server/api.sock"}
2022-12-13T00:41:21.764Z INFO controller-runtime.metrics metrics server is starting to listen {"addr": "127.0.0.1:8082"}
2022-12-13T00:41:21.807Z INFO webhook-manager Minting webhook certificate {"reason": "initializing", "dnsNames": ["spire-controller-manager-webhook-service.spire.svc"]}
2022-12-13T00:41:21.828Z INFO webhook-manager Minted webhook certificate
2022-12-13T00:41:21.844Z INFO webhook-manager Webhook configuration patched with CABundleI'm using CRD mode Kubernetes Workload Registrar, and it gets stuck deleting the SpiffeId CRD. What do I do?
This can happen if the Kubernetes Workload Registrar is deleted before all the SpiffeId custom resources are removed. To get around this, manually remove the finalizers with the below script and try deleting the CRD again.
for ns in $(kubectl get ns | awk '{print $1}' | tail -n +2)
do
if [ $(kubectl get spiffeids -n $ns 2>/dev/null | wc -l) -ne 0 ]
then
kubectl patch spiffeid $(kubectl get spiffeids -n $ns | awk '{print $1}' | tail -n +2) --type='merge' -p '{"metadata":{"finalizers":null}}' -n $ns
fi
doneSPIRE Controller Manager uses a different scheme for parenting SPIFFE IDs. Though it is technically possible to modify all the entries, it's a lot easier to just allow SPIRE Controller Manager to automatically replace the entries.
SPIRE Controller Manager will reconcile the state of the system when it starts up. Any new Pods deployed after Kubernetes Workload Registrar is deleted and before SPIRE Controller Manager is up will have entries created when SPIRE Controller Manager is up.