SPIRE
SPIREは、異種環境で実行されているワークロードに暗号化されたIDを安全に発行するために、ノードとワークロードの証明を実行する、SPIFFE仕様のプロダクション対応実装です。 SPIREは、EnvoyのSDS APIとの統合を通じて、Istioワークロードの暗号化IDのソースとして構成できます。 Istioは、定義されたソケットパスでEnvoy SDS APIを実装するUNIXドメインソケットの存在を検出できるため、Envoyはそれと直接通信してIDをフェッチできます。
このSPIREとの統合により、Istioの強力なサービス管理を活用しながら、デフォルトのIstioのID管理では利用できない柔軟な証明オプションが提供されます。例えば、SPIREのプラグインアーキテクチャにより、Istioが提供するKubernetes名前空間やサービスアカウントの証明を超えた、多様なワークロード証明オプションが可能になります。SPIREのノード証明は、ワークロードが実行される物理または仮想ハードウェアにまで証明を拡張します。
このSPIREとIstioの統合がどのように機能するかの簡単なデモについては、EnvoyのSDS APIを介してSPIREをCAとして統合するをご覧ください。
SPIREのインストール
SPIREのインストール、および本番環境へのSPIREのデプロイについては、SPIREのインストール手順とベストプラクティスに従うことをお勧めします。
このガイドの例では、SPIREとIstioを統合するために必要な設定のみに焦点を当てるため、SPIRE Helmチャートをアップストリームのデフォルト設定で使用します。
$ helm upgrade --install -n spire-server spire-crds spire-crds --repo https://spiffe.github.io/helm-charts-hardened/ --create-namespace
$ helm upgrade --install -n spire-server spire spire --repo https://spiffe.github.io/helm-charts-hardened/ --wait --set global.spire.trustDomain="example.org"
デフォルトでは、上記に加えて以下もインストールされます。
SPIFFE CSIドライバー。これは、Envoy互換のSDSソケットをプロキシにマウントするために使用されます。
hostMounts
はセキュリティリスクが大きく、運用上のハードルも発生するため、SDSソケットをマウントするためにSPIFFE CSIドライバーを使用することをIstioとSPIREの両方が強く推奨しています。このガイドでは、SPIFFE CSIドライバーの使用を前提としています。SPIRE Controller Manager。これにより、ワークロードのSPIFFE登録の作成が容易になります。
ワークロードの登録
設計上、SPIREは、SPIREサーバーに登録されたワークロードにのみIDを付与します。これには、ユーザーワークロードだけでなく、Istioコンポーネントも含まれます。SPIRE統合用に設定されたIstioサイドカーとゲートウェイは、事前に作成された既存の一致するSPIRE登録がない限り、IDを取得できず、したがってREADYステータスに到達できません。
複数のセレクターを使用して証明基準を強化する方法、および利用可能なセレクターの詳細については、ワークロードを登録するためのSPIREドキュメントを参照してください。
このセクションでは、SPIREサーバーにIstioワークロードを登録するために利用できるオプションについて説明し、いくつかのワークロード登録の例を示します。
オプション1:SPIREコントローラーマネージャーを使用した自動登録
新しいエントリは、ClusterSPIFFEIDカスタムリソースで定義されたセレクターに一致する新しいポッドごとに自動的に登録されます。
IstioサイドカーとIstioゲートウェイの両方をSPIREに登録して、IDを要求できるようにする必要があります。
Istioゲートウェイ ClusterSPIFFEID
以下では、istio-system
名前空間にスケジュールされ、istio-ingressgateway-service-account
という名前のサービスアカウントを持つIstio IngressゲートウェイポッドをSPIREに自動登録するClusterSPIFFEID
を作成します。これらのセレクターは簡単な例として使用されています。SPIRE Controller Managerのドキュメントで詳細を確認してください。
$ kubectl apply -f - <<EOF
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
name: istio-ingressgateway-reg
spec:
spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
workloadSelectorTemplates:
- "k8s:ns:istio-system"
- "k8s:sa:istio-ingressgateway-service-account"
EOF
Istioサイドカー ClusterSPIFFEID
以下では、spiffe.io/spire-managed-identity: true
ラベルを持つポッドで、default
名前空間にデプロイされたものをSPIREに自動登録するClusterSPIFFEID
を作成します。これらのセレクターは簡単な例として使用されています。SPIRE Controller Managerのドキュメントで詳細を確認してください。
$ kubectl apply -f - <<EOF
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
name: istio-sidecar-reg
spec:
spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
podSelector:
matchLabels:
spiffe.io/spire-managed-identity: "true"
workloadSelectorTemplates:
- "k8s:ns:default"
EOF
オプション2:手動登録
推奨オプションで言及されているSPIRE Controller Managerを使用するのではなく、SPIRE登録を手動で作成する場合は、手動登録に関するSPIREドキュメントを参照してください。
以下は、オプション1の自動登録に基づいた、同等の手動登録です。以下の手順では、SPIREエージェントとノード証明を手動で登録するためのSPIREドキュメントにすでに従っていること、およびSPIREエージェントがSPIFFE ID spiffe://example.org/ns/spire/sa/spire-agent
で登録されていることを前提としています。
spire-server
ポッドを取得します。$ SPIRE_SERVER_POD=$(kubectl get pod -l statefulset.kubernetes.io/pod-name=spire-server-0 -n spire-server -o jsonpath="{.items[0].metadata.name}")
Istio Ingressゲートウェイポッドのエントリを登録します。
$ kubectl exec -n spire "$SPIRE_SERVER_POD" -- \ /opt/spire/bin/spire-server entry create \ -spiffeID spiffe://example.org/ns/istio-system/sa/istio-ingressgateway-service-account \ -parentID spiffe://example.org/ns/spire/sa/spire-agent \ -selector k8s:sa:istio-ingressgateway-service-account \ -selector k8s:ns:istio-system \ -socketPath /run/spire/sockets/server.sock Entry ID : 6f2fe370-5261-4361-ac36-10aae8d91ff7 SPIFFE ID : spiffe://example.org/ns/istio-system/sa/istio-ingressgateway-service-account Parent ID : spiffe://example.org/ns/spire/sa/spire-agent Revision : 0 TTL : default Selector : k8s:ns:istio-system Selector : k8s:sa:istio-ingressgateway-service-account
Istioサイドカーが注入されたワークロードのエントリを登録します。
$ kubectl exec -n spire "$SPIRE_SERVER_POD" -- \ /opt/spire/bin/spire-server entry create \ -spiffeID spiffe://example.org/ns/default/sa/curl \ -parentID spiffe://example.org/ns/spire/sa/spire-agent \ -selector k8s:ns:default \ -selector k8s:pod-label:spiffe.io/spire-managed-identity:true \ -socketPath /run/spire/sockets/server.sock
Istioのインストール
Ingressゲートウェイと
istio-proxy
用のカスタムパッチを使用してIstio構成を作成します。Ingressゲートウェイコンポーネントには、spiffe.io/spire-managed-identity: "true"
ラベルが含まれています。$ cat <<EOF > ./istio.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: namespace: istio-system spec: profile: default meshConfig: trustDomain: example.org values: # This is used to customize the sidecar template. # It adds both the label to indicate that SPIRE should manage the # identity of this pod, as well as the CSI driver mounts. sidecarInjectorWebhook: templates: spire: | labels: spiffe.io/spire-managed-identity: "true" spec: containers: - name: istio-proxy volumeMounts: - name: workload-socket mountPath: /run/secrets/workload-spiffe-uds readOnly: true volumes: - name: workload-socket csi: driver: "csi.spiffe.io" readOnly: true components: ingressGateways: - name: istio-ingressgateway enabled: true label: istio: ingressgateway k8s: overlays: # This is used to customize the ingress gateway template. # It adds the CSI driver mounts, as well as an init container # to stall gateway startup until the CSI driver mounts the socket. - apiVersion: apps/v1 kind: Deployment name: istio-ingressgateway patches: - path: spec.template.spec.volumes.[name:workload-socket] value: name: workload-socket csi: driver: "csi.spiffe.io" readOnly: true - path: spec.template.spec.containers.[name:istio-proxy].volumeMounts.[name:workload-socket] value: name: workload-socket mountPath: "/run/secrets/workload-spiffe-uds" readOnly: true - path: spec.template.spec.initContainers value: - name: wait-for-spire-socket image: busybox:1.36 volumeMounts: - name: workload-socket mountPath: /run/secrets/workload-spiffe-uds readOnly: true env: - name: CHECK_FILE value: /run/secrets/workload-spiffe-uds/socket command: - sh - "-c" - |- echo "$(date -Iseconds)" Waiting for: ${CHECK_FILE} while [[ ! -e ${CHECK_FILE} ]] ; do echo "$(date -Iseconds)" File does not exist: ${CHECK_FILE} sleep 15 done ls -l ${CHECK_FILE} EOF
構成を適用します。
$ istioctl install --skip-confirmation -f ./istio.yaml
Ingressゲートウェイポッドの状態を確認します。
$ kubectl get pods -n istio-system NAME READY STATUS RESTARTS AGE istio-ingressgateway-5b45864fd4-lgrxs 1/1 Running 0 17s istiod-989f54d9c-sg7sn 1/1 Running 0 23s
Ingressゲートウェイポッドは、対応する登録エントリがSPIREサーバーで自動的に作成されるため、
Ready
になります。EnvoyはSPIREから暗号化されたIDを取得できます。この構成では、
istio-proxy
を開始する前に、SPIREがUNIXドメインソケットを作成するのを待つinitContainer
もゲートウェイに追加されます。SPIREエージェントの準備ができていない場合、または同じソケットパスで適切に構成されていない場合、IngressゲートウェイのinitContainer
は永久に待機します。ワークロードの例をデプロイします。
$ istioctl kube-inject --filename @samples/security/spire/curl-spire.yaml@ | kubectl apply -f -
spiffe.io/spire-managed-identity
ラベルが必要なことに加えて、ワークロードはSPIREエージェントソケットにアクセスするためにSPIFFE CSIドライバーボリュームを必要とします。これを実現するには、Istioのインストールセクションのspire
ポッドアノテーションテンプレートを利用するか、ワークロードのデプロイスペックにCSIボリュームを追加できます。これらの代替案の両方が、以下の例のスニペットで強調表示されています。apiVersion: apps/v1 kind: Deployment metadata: name: curl spec: replicas: 1 selector: matchLabels: app: curl template: metadata: labels: app: curl # Injects custom sidecar template annotations: inject.istio.io/templates: "sidecar,spire" spec: terminationGracePeriodSeconds: 0 serviceAccountName: curl containers: - name: curl image: curlimages/curl command: ["/bin/sleep", "3650d"] imagePullPolicy: IfNotPresent volumeMounts: - name: tmp mountPath: /tmp securityContext: runAsUser: 1000 volumes: - name: tmp emptyDir: {} # CSI volume - name: workload-socket csi: driver: "csi.spiffe.io" readOnly: true
Istio構成は、Ingressゲートウェイとワークロードポッドに注入されるサイドカーとspiffe-csi-driver
を共有し、SPIREエージェントのUNIXドメインソケットへのアクセスを許可します。
発行されたIDを確認するには、ワークロード用にIDが作成されたことを確認するを参照してください。
ワークロードにIDが作成されたことを確認する
次のコマンドを使用して、ワークロード用にIDが作成されたことを確認します。
$ kubectl exec -t "$SPIRE_SERVER_POD" -n spire-server -c spire-server -- ./bin/spire-server entry show
Found 2 entries
Entry ID : c8dfccdc-9762-4762-80d3-5434e5388ae7
SPIFFE ID : spiffe://example.org/ns/istio-system/sa/istio-ingressgateway-service-account
Parent ID : spiffe://example.org/spire/agent/k8s_psat/demo-cluster/bea19580-ae04-4679-a22e-472e18ca4687
Revision : 0
X509-SVID TTL : default
JWT-SVID TTL : default
Selector : k8s:pod-uid:88b71387-4641-4d9c-9a89-989c88f7509d
Entry ID : af7b53dc-4cc9-40d3-aaeb-08abbddd8e54
SPIFFE ID : spiffe://example.org/ns/default/sa/curl
Parent ID : spiffe://example.org/spire/agent/k8s_psat/demo-cluster/bea19580-ae04-4679-a22e-472e18ca4687
Revision : 0
X509-SVID TTL : default
JWT-SVID TTL : default
Selector : k8s:pod-uid:ee490447-e502-46bd-8532-5a746b0871d6
Ingress-gatewayポッドの状態を確認します。
$ kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
istio-ingressgateway-5b45864fd4-lgrxs 1/1 Running 0 60s
istiod-989f54d9c-sg7sn 1/1 Running 0 45s
Ingress-gatewayポッドのエントリを登録すると、EnvoyはSPIREによって発行されたIDを受け取り、すべてのTLSおよびmTLS通信に使用します。
ワークロードIDがSPIREによって発行されたことを確認する
ポッド情報を取得します。
$ CURL_POD=$(kubectl get pod -l app=curl -o jsonpath="{.items[0].metadata.name}")
istioctl proxy-config secretコマンドを使用して、curlのSVID IDドキュメントを取得します。
$ istioctl proxy-config secret "$CURL_POD" -o json | jq -r \ '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' | base64 --decode > chain.pem
証明書を検査し、SPIREが発行者であることを確認します。
$ openssl x509 -in chain.pem -text | grep SPIRE Subject: C = US, O = SPIRE, CN = curl-5f4d47c948-njvpk
SPIFFEフェデレーション
SPIREサーバーは、異なるトラストドメインから発信されたSPIFFE IDを認証できます。これはSPIFFEフェデレーションとして知られています。
SPIREエージェントは、Envoy SDS APIを介してフェデレーションバンドルをEnvoyにプッシュするように構成できるため、Envoyは検証コンテキストを使用してピア証明書を検証し、別のトラストドメインからのワークロードを信頼できます。IstioがSPIRE統合を介してSPIFFE IDをフェデレーションできるようにするには、SPIREエージェントのSDS構成を参照し、SPIREエージェント構成ファイルに次のSDS構成値を設定します。
構成 | 説明 | リソース名 |
---|---|---|
default_svid_name | Envoy SDSでデフォルトのX509-SVID に使用するTLS証明書リソース名 | default |
default_bundle_name | Envoy SDSでデフォルトのX.509バンドルに使用する検証コンテキストリソース名 | null |
default_all_bundles_name | Envoy SDSですべてのバンドル(フェデレーションを含む)に使用する検証コンテキストリソース名 | ROOTCA |
これにより、EnvoyはSPIREから直接フェデレーションバンドルを取得できるようになります。
フェデレーション登録エントリの作成
SPIRE Controller Managerを使用している場合は、ClusterSPIFFEID CRの
federatesWith
フィールドを、ポッドがフェデレーションするトラストドメインに設定することで、ワークロードのフェデレーションエントリを作成します。apiVersion: spire.spiffe.io/v1alpha1 kind: ClusterSPIFFEID metadata: name: federation spec: spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}" podSelector: matchLabels: spiffe.io/spire-managed-identity: "true" federatesWith: ["example.io", "example.ai"]
手動登録については、フェデレーションの登録エントリを作成するを参照してください。
SPIREのクリーンアップ
SPIREのHelmチャートをアンインストールして、SPIREを削除します。
$ helm delete -n spire-server spire
$ helm delete -n spire-server spire-crds