diff --git a/charts/spire/templates/agent-configmap.tpl b/charts/spire/templates/agent-configmap.tpl index e759b02f..918eb4bd 100644 --- a/charts/spire/templates/agent-configmap.tpl +++ b/charts/spire/templates/agent-configmap.tpl @@ -24,6 +24,13 @@ data: plugin_data { } } + {{- else if .Values.x509 }} + NodeAttestor "x509pop" { + plugin_data { + private_key_path = "/run/spire/agent/node.key.pem" + certificate_path = "/run/spire/agent/node-bundle.cert.pem" + } + } {{- else }} NodeAttestor "k8s_psat" { plugin_data { diff --git a/charts/spire/templates/agent-daemonset.tpl b/charts/spire/templates/agent-daemonset.tpl index cbf91745..9616d9f3 100644 --- a/charts/spire/templates/agent-daemonset.tpl +++ b/charts/spire/templates/agent-daemonset.tpl @@ -46,6 +46,10 @@ spec: readOnly: true - name: spire-agent-token mountPath: /var/run/secrets/tokens + readOnly: true + - name: agent-x509 + mountPath: /run/spire/agent + readOnly: true livenessProbe: exec: command: @@ -68,6 +72,10 @@ spec: hostPath: path: {{ .Values.spireAgent.socketDir }} type: DirectoryOrCreate + - name: agent-x509 + hostPath: + path: /run/spire/x509 + type: Directory - name: spire-agent-token projected: sources: diff --git a/charts/spire/values.yaml b/charts/spire/values.yaml index d580707f..7c88397d 100644 --- a/charts/spire/values.yaml +++ b/charts/spire/values.yaml @@ -17,7 +17,7 @@ region: sample-region # SPIRE server trustdomain: spiretest.com # SPIRE version: -spireVersion: 1.0.2 +spireVersion: 1.1.3 # spireServer - location of the SPIRE server spireServer: diff --git a/charts/tornjak/templates/server-configmap.tpl b/charts/tornjak/templates/server-configmap.tpl index 0c9796a3..c017370f 100644 --- a/charts/tornjak/templates/server-configmap.tpl +++ b/charts/tornjak/templates/server-configmap.tpl @@ -18,6 +18,8 @@ data: data_dir = "/run/spire/data" log_level = "DEBUG" default_svid_ttl = "1h" + # extended to 7 days, just for testing + ca_ttl = "168h" socket_path = "{{ .Values.spireServer.socketDir }}/{{ .Values.spireServer.socketFile }}" {{- if .Values.oidc.enable }} @@ -70,6 +72,11 @@ data: } } } + NodeAttestor "x509pop" { + plugin_data { + ca_bundle_path = "/opt/spire/sample-x509/rootCA.pem" + } + } {{- if .Values.attestors.aws_iid -}} {{- if .Values.attestors.aws_iid.access_key_id -}} diff --git a/charts/tornjak/templates/server-statefulset.tpl b/charts/tornjak/templates/server-statefulset.tpl index d7b619fb..61a138c8 100644 --- a/charts/tornjak/templates/server-statefulset.tpl +++ b/charts/tornjak/templates/server-statefulset.tpl @@ -33,6 +33,8 @@ spec: # not needed if using volumeClaimTemplates and sockets privileged: true volumeMounts: + - name: sample-x509 + mountPath: /opt/spire/sample-x509 - name: spire-config mountPath: /run/spire/config readOnly: true @@ -124,6 +126,10 @@ spec: mountPath: {{ .Values.oidc.socketDir }} {{- end }} volumes: + - name: sample-x509 + secret: + defaultMode: 0400 + secretName: sample-x509 - name: spire-config configMap: name: spire-server diff --git a/charts/tornjak/values.yaml b/charts/tornjak/values.yaml index 64eca7d5..68684035 100644 --- a/charts/tornjak/values.yaml +++ b/charts/tornjak/values.yaml @@ -14,15 +14,13 @@ clustername: spire-example # trustdomain is arbitrary but needs to match between Server and Agent trustdomain: spiretest.com # SPIRE version used for consistency across components -spireVersion: 1.0.2 +spireVersion: 1.1.3 # SPIRE Server configuration spireServer: # tornjakImage - Tornjak with SPIRE Server - # TODO this is just a temporary image with several patches. It - # should be removed after the patches are available in the SPIRE main - # img: ghcr.io/spiffe/tornjak-spire-server - img: tsidentity/local-spire-server + img: ghcr.io/spiffe/tornjak-spire-server + socketDir: /run/spire-server/private socketFile: api.sock # selfSignedCA - SPIRE will create the self signed CA unless this value diff --git a/docs/spire-workload-registrar.md b/docs/spire-workload-registrar.md index 6cf26ddc..e70cf35e 100644 --- a/docs/spire-workload-registrar.md +++ b/docs/spire-workload-registrar.md @@ -152,6 +152,76 @@ or delete them, if needed, using `Entry ID` value: -socketPath /run/spire/sockets/registration.sock ``` +## IMPORTANT: For non-k8s node attestors +When using NodeAttestor other than *k8s_psa* +you must create entries to tie your agents to the parent ID with specific attestation +(see issue [852](https://github.com/spiffe/spire/issues/852)) + +Once the workload registrar entry is created (as above), +the registrar will create entries for each node. +For example: +* spiffe://openshift.space-x.com/k8s-workload-registrar/spire-01/node/10.170.231.21 + - k8s_psat:cluster:spire-01 + - k8s_psat:agent_node_uid:7f450925-f3b3-4274-bfe9-e9d09bafbc12 +* spiffe://openshift.space-x.com/k8s-workload-registrar/spire-01/node/10.170.231.14 + - k8s_psat:cluster:spire-01 + - k8s_psat:agent_node_uid:c8b69816-f5f9-4e90-aaa1-6445d5bba11a + +with `spiffe://openshift.space-x.com/spire/server` as Parent ID + +Now we have to create new entries that would tie the above SPIFFE IDs to the +attested entries. +Look at the agent list and gather the selectors: + +For example, agents: +``` +* spiffe://openshift.space-x.com/spire/agent/x509pop/ca34d6728cf332689646010a1d9012d8fa449a3f + +"selectors": [ + { + "type": "x509pop", + "value": "ca:fingerprint:42cd4a9e007c67a52bfb28cf3f4a8cfd576fbfd2" + }, + { + "type": "x509pop", + "value": "ca:fingerprint:df27569b5adc9c44db043ea1f509c9f79a049e2d" + }, + { + "type": "x509pop", + "value": "subject:cn:some common name1" + } + +* spiffe://openshift.space-x.com/spire/agent/x509pop/1753fc2737195744cd52942d9723e1d7d2804249 + +"selectors": [ + { + "type": "x509pop", + "value": "ca:fingerprint:42cd4a9e007c67a52bfb28cf3f4a8cfd576fbfd2" + }, + { + "type": "x509pop", + "value": "ca:fingerprint:df27569b5adc9c44db043ea1f509c9f79a049e2d" + }, + { + "type": "x509pop", + "value": "subject:cn:some common name2" + } +] +``` + +So now we have to tie them together. Create new entries, one per each node: + +For example (pick one of the selector values to guarantee uniqueness): + +* SPIFFE ID: spiffe://openshift.space-x.com/k8s-workload-registrar/spire-01/node/10.170.231.14 + - Parent ID: spiffe://openshift.space-x.com/spire/agent/x509pop/1753fc2737195744cd52942d9723e1d7d2804249 + - Selectors: x509pop:ca:fingerprint:42cd4a9e007c67a52bfb28cf3f4a8cfd576fbfd2 +* SPIFFE ID: spiffe://openshift.space-x.com/k8s-workload-registrar/spire-01/node/10.170.231.21 + - Parent ID: spiffe://openshift.space-x.com/spire/agent/x509pop/ca34d6728cf332689646010a1d9012d8fa449a3f + - Selectors: x509pop:subject:cn:"some common name1" + +No ADMIN selection required. + ## Create sample deployment To see this environment in action, let’s deploy a sample workload with a simple SPIRE client. This example starts a pod that contains SPIRE agent binaries. We can use them to get SPIFFE identity. Before deploying the client, let’s take a look at the deployment file: diff --git a/docs/x509-create.md b/docs/x509-create.md index 282762d8..5aba5e4e 100644 --- a/docs/x509-create.md +++ b/docs/x509-create.md @@ -30,6 +30,16 @@ The steps are following: ### Generating RootCA +This example comes with sample x509 certificates and keys to demonstrate +`x509pop` nodeAttestor capabilities. + +The sample keys are present in [../sample-x509](../sample-x509) directory. +You can create a new set of certs and keys: +* [using a script](#generate_keys_using_a_script) +* [manually (recommended)](#generate_keys_manually) + +## Generate keys using a script +To create new sample certs and keys: ```console mkdir x509/ca cd x509/ca diff --git a/docs/x509.md b/docs/x509.md new file mode 100644 index 00000000..37f3b263 --- /dev/null +++ b/docs/x509.md @@ -0,0 +1,87 @@ +# Tornjak + SPIRE with x509pop (Proof of Possession) for Confidential Computing project +The `x509pop` nodeAttestor plugin attests nodes that have been provisioned with +an x509 identity through an out-of-band mechanism. +It verifies that the certificate is rooted to a trusted set of CAs +and issues a signature based proof-of-possession challenge to the agent plugin +to verify that the node is in possession of the private key. + +## Index +* Create x509 certs and keys using a script +* Create x509 certs and keys manually (recommended) +* Deploy the + +## Pre-install: Get the code and create Keys +### Get the code +Obtain the clone of the repo: + +```console +git clone https://github.com/IBM/trusted-service-identity.git +git checkout conf_container +``` +### Create keys and certificates for testing +Keys are already created in `sample-x509` directory. + +The script for generating keys is based on: +https://github.com/spiffe/spire/blob/v1.2.0/test/fixture/nodeattestor/x509pop/generate.go + +To create new sample keys: +```console +cd sample-x509 +go run generate.go +cd .. +``` + +Setting up the keys for SPIRE Server: +* generate rootCA key +* create rootCert (rootKey) +* generate intermediate Key +* create intermediateCert(intermKey, rootKey, rootCert) + + +## Install the SPIRE Server with OIDC and Vault +Create a new namespace +```console +kubectl create ns tornjak +``` + +Server NodeAttestor just needs the rootCA cert for verification (rootCA.pem) + +Pass the cert as a Secret: +```console + +kubectl -n tornjak create secret generic sample-x509 \ +--from-file=rootCA.pem="sample-x509/root.cert.pem" +``` + +### Server deployment +Here we are using OpenShift cluster in IBM Cloud. +Setup `KUBECONFIG` and deploy: + +```console +# use a script to get CLUSTER_NAME +utils/get-cluster-info.sh + +# or set it up explicitly: +export CLUSTER_NAME=openshift-ibmcloud-01 +utils/install-open-shift-tornjak.sh -c $CLUSTER_NAME -t openshift.space-x.com --oidc +``` + +Test access to Tornjak and OIDC, as shown at the end of the deployment. + +Capture the `spire-bundle` to be used for Spire Agents: + +```console +kubectl -n tornjak get configmap spire-bundle -oyaml | kubectl patch --type json --patch '[{"op": "replace", "path": "/metadata/namespace", "value":"spire"}]' -f - --dry-run=client -oyaml > spire-bundle.yaml +``` + +### Setup Vault with OIDC: +https://github.com/IBM/trusted-service-identity/blob/main/docs/spire-oidc-vault.md + +## Deploy SPIRE Agents in Remote Clusters +Follow the deployment of [agent with x509](./x509-agent.md) + +### To cleanup the cluster (removes everything) + +```console +utils/install-open-shift-tornjak.sh --clean +``` diff --git a/utils/install-open-shift-spire.sh b/utils/install-open-shift-spire.sh index 5e727c8e..de802711 100755 --- a/utils/install-open-shift-spire.sh +++ b/utils/install-open-shift-spire.sh @@ -182,7 +182,8 @@ oc_cli adm policy add-scc-to-user privileged -z $SPIRE_AG_SA helm install --set "spireServer.address=$SPIRESERVER" --set "namespace=$PROJECT" \ --set "clustername=$CLUSTERNAME" --set "trustdomain=$TRUSTDOMAIN" \ --set "region=$REGION" \ - --set "openShift=true" spire charts/spire # --debug + --set "x509=true" \ + --set "openShift=true" spire charts/spire --debug cat << EOF diff --git a/utils/install-open-shift-tornjak.sh b/utils/install-open-shift-tornjak.sh index 6ad7dadb..c0509f56 100755 --- a/utils/install-open-shift-tornjak.sh +++ b/utils/install-open-shift-tornjak.sh @@ -218,8 +218,10 @@ echo "$INGRESS" # setup TLS secret: CRN=$(ibmcloud oc ingress secret get -c "$CLUSTERNAME" --name "$INGSEC" --namespace openshift-ingress --output json | jq -r '.crn') + # not needed for k8s 1.22 anymore: #ibmcloud oc ingress secret create --cluster "$CLUSTERNAME" --cert-crn "$CRN" --name "$INGSEC" --namespace "$PROJECT" + if [ "$?" == "0" ]; then echo "All good" fi @@ -230,6 +232,8 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: spireingress + annotations: + kubernetes.io/ingress.class: "public-iks-k8s-nginx" spec: tls: - hosts: