SPIFFEのチュートリアルを試したメモ

以下ブログを翻訳しようとしたが、SPIFFEが全然わからなかったので、SPIFFEのチュートリアルを試したメモ。

参考リンク

手順

クラスターの作成

今回はMinikubeでやってみる。注意点として記載があるとおり、いくつかフラグをつけて起動する。

$ minikube start \
>     --extra-config=apiserver.service-account-signing-key-file=/var/lib/minikube/certs/sa.key \
>     --extra-config=apiserver.service-account-key-file=/var/lib/minikube/certs/sa.pub \
>     --extra-config=apiserver.service-account-issuer=api \
>     --extra-config=apiserver.service-account-api-audiences=api,spire-server \
>     --extra-config=apiserver.authorization-mode=Node,RBAC
😄  Darwin 10.14.6 上の minikube v1.18.1
✨  dockerドライバーが自動的に選択されました。他の選択肢:  hyperkit, virtualbox, ssh
👍  コントロールプレーンのノード minikube を minikube 上で起動しています
🚜  Pulling base image ...
💾  Kubernetes v1.20.2 のダウンロードの準備をしています
    > preloaded-images-k8s-v9-v1....: 491.22 MiB / 491.22 MiB  100.00% 25.98 Mi
🔥  docker container (CPUs=2, Memory=3890MB) を作成しています...
🐳  Docker 20.10.3 で Kubernetes v1.20.2 を準備しています...
    ▪ apiserver.service-account-signing-key-file=/var/lib/minikube/certs/sa.key
    ▪ apiserver.service-account-key-file=/var/lib/minikube/certs/sa.pub
    ▪ apiserver.service-account-issuer=api
    ▪ apiserver.service-account-api-audiences=api,spire-server
    ▪ apiserver.authorization-mode=Node,RBAC
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔎  Kubernetes コンポーネントを検証しています...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v4
🌟  有効なアドオン: default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

リポジトリのクローン

リポジトリをクローンする。

git clone https://github.com/spiffe/spire-tutorials
cd spire-tutorials/k8s/quickstart

サーバーの構成

Namespaceを作成する。

$ kubectl apply -f spire-namespace.yaml
namespace/spire created
$ k get ns
NAME              STATUS   AGE
default           Active   9m14s
kube-node-lease   Active   9m15s
kube-public       Active   9m16s
kube-system       Active   9m16s
spire             Active   8s

SPIREサーバー用のServiceAccountCondfigMapClusterRole/ClusterRoleBindingを作成する。

$ kubectl apply \
>     -f server-account.yaml \
>     -f spire-bundle-configmap.yaml \
>     -f server-cluster-role.yaml
serviceaccount/spire-server created
configmap/spire-bundle created
clusterrole.rbac.authorization.k8s.io/spire-server-trust-role created
clusterrolebinding.rbac.authorization.k8s.io/spire-server-trust-role-binding created

SPIREサーバーのConfigMapStatefulSetServiceを作成する。

$ kubectl apply \
>     -f server-configmap.yaml \
>     -f server-statefulset.yaml \
>     -f server-service.yaml
configmap/spire-server created
statefulset.apps/spire-server created
service/spire-server created

確認する。

$  kubectl get statefulset --namespace spire
NAME           READY   AGE
spire-server   1/1     20s
$ kubectl get pods --namespace spire
NAME             READY   STATUS    RESTARTS   AGE
spire-server-0   1/1     Running   0          30s
$ kubectl get services --namespace spire
NAME           TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
spire-server   NodePort   10.106.188.29   <none>        8081:31210/TCP   37s

エージェントの構成

SPIREエージェント用のServiceAccountClusterRole/ClusterRoleBindingを作成する。

$ kubectl apply \
>     -f agent-account.yaml \
>     -f agent-cluster-role.yaml
serviceaccount/spire-agent created
clusterrole.rbac.authorization.k8s.io/spire-agent-cluster-role created
clusterrolebinding.rbac.authorization.k8s.io/spire-agent-cluster-role-binding created

SPIREエージェントのConfigMapDaemonSetを作成する。

$ kubectl apply \
>     -f agent-configmap.yaml \
>     -f agent-daemonset.yaml
configmap/spire-agent created
daemonset.apps/spire-agent created

確認する。

$ kubectl get daemonset --namespace spire
NAME          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
spire-agent   1         1         1       1            1           <none>          114s
$ kubectl get pods --namespace spire
NAME                READY   STATUS    RESTARTS   AGE
spire-agent-fx88v   1/1     Running   0          2m
spire-server-0      1/1     Running   0          7m39s

ワークロードの登録

最初にワークロードをサーバーに登録する必要がある。

ノードに割り当てるSPIFFEIDを指定して、ノードの新しい登録エントリーを作成する。

$ kubectl exec -n spire spire-server-0 -- \
>     /opt/spire/bin/spire-server entry create \
>     -spiffeID spiffe://example.org/ns/spire/sa/spire-agent \
>     -selector k8s_sat:cluster:demo-cluster \
>     -selector k8s_sat:agent_ns:spire \
>     -selector k8s_sat:agent_sa:spire-agent \
>     -node
Entry ID         : dbd74f07-f3ce-4dcf-b6c1-1a78f062dfe1
SPIFFE ID        : spiffe://example.org/ns/spire/sa/spire-agent
Parent ID        : spiffe://example.org/spire/server
Revision         : 0
TTL              : default
Selector         : k8s_sat:agent_ns:spire
Selector         : k8s_sat:agent_sa:spire-agent
Selector         : k8s_sat:cluster:demo-cluster

ワークロードに割り当てるSPIFFEIDを指定して、ワークロードの新しい登録エントリを作成する。

$ kubectl exec -n spire spire-server-0 -- \
>     /opt/spire/bin/spire-server entry create \
>     -spiffeID spiffe://example.org/ns/default/sa/default \
>     -parentID spiffe://example.org/ns/spire/sa/spire-agent \
>     -selector k8s:ns:default \
>     -selector k8s:sa:default
Entry ID         : f5ef86a6-9b8f-4a0a-b503-2c9a3e2dd476
SPIFFE ID        : spiffe://example.org/ns/default/sa/default
Parent ID        : spiffe://example.org/ns/spire/sa/spire-agent
Revision         : 0
TTL              : default
Selector         : k8s:ns:default
Selector         : k8s:sa:default

ワークロードコンテナの構成

SPIREにアクセスするようにワークロードコンテナを構成する。

クライアントのDeploymentを作成する。

$ kubectl apply -f client-deployment.yaml
deployment.apps/client created

マニフェストを見ると、ホストの/run/spire/socketsをマウントしていて、hostPID: truehostNetwork: trueが設定されている。

Podに接続する。

kubectl exec -it $(kubectl get pods -o=jsonpath='{.items[0].metadata.name}' \
   -l app=client)  -- /bin/sh

ソケットにアクセスしSVIDが取得できることを確認する。

/opt/spire # /opt/spire/bin/spire-agent api fetch -socketPath /run/spire/sockets/agent.sock
Received 1 svid after 10.535ms

SPIFFE ID:              spiffe://example.org/ns/default/sa/default
SVID Valid After:       2021-03-24 13:42:52 +0000 UTC
SVID Valid Until:       2021-03-24 14:43:02 +0000 UTC
CA #1 Valid After:      2021-03-24 13:30:48 +0000 UTC
CA #1 Valid Until:      2021-03-25 13:30:58 +0000 UTC

/opt/spire # 

以上でチュートリアルは終了。

-writeで証明書を保存できる。

/opt/spire # /opt/spire/bin/spire-agent api fetch x509 -socketPath /run/spire/sockets/agent.sock -write /tmp/
Received 1 svid after 16.7911ms

SPIFFE ID:              spiffe://example.org/ns/default/sa/default
SVID Valid After:       2021-03-24 13:42:52 +0000 UTC
SVID Valid Until:       2021-03-24 14:43:02 +0000 UTC
CA #1 Valid After:      2021-03-24 13:30:48 +0000 UTC
CA #1 Valid Until:      2021-03-25 13:30:58 +0000 UTC

Writing SVID #0 to file /tmp/svid.0.pem.
Writing key #0 to file /tmp/svid.0.key.
Writing bundle #0 to file /tmp/bundle.0.pem.
/opt/spire #